首先看如下代碼示例:
1
2
3
4
|
System.out.println( 0.05 + 0.01 ); System.out.println( 0.05 - 0.03 ); System.out.println( 1.025 * 100 ); System.out.println( 305.1 / 1000 ); |
輸出結果為:
0.060000000000000005
0.020000000000000004
102.49999999999999
0.30510000000000004
Java語言支持兩種基本的浮點類型:float和double,以及與它們對應的包裝類Float和Double。它們都依據IEEE 754 標準,該標準為 32 位浮點和 64 位雙精度浮點二進制小數定義了二進制標準。
IEEE 754 用科學記數法以底數為 2 的小數來表示浮點數。IEEE 浮點數用 1 位表示數字的符號,用 8 位來表示指數,用 23 位來表示尾數,即小數部分,作為有符號整數的指數可以有正負之分,小數部分用二進制(底數 2)小數來表示
不要用浮點值表示精確值
一些非整數值(如幾美元和幾美分這樣的小數)需要很精確。浮點數不是精確值,所以使用它們會導致舍入誤差。因此,使用浮點數來試圖表示象貨幣量這樣的精確數量不是一個好的想法。使用浮點數來進行美元和美分計算會得到災難性的后果。浮點數最好用來表示象測量值這類數值,這類值從一開始就不怎么精確。
從 JDK 1.3 起,Java 開發人員就有了另一種數值表示法來表示非整數: BigDecimal 。 BigDecimal 是標準的類,在編譯器中不需要特殊支持,它可以表示任意精度的小數,并對它們進行計算。
用于加、減、乘和除的方法給 BigDecimal 值提供了算術運算。由于 BigDecimal 對象是不可變的,這些方法中的每一個都會產生新的 BigDecimal 對象。因此,因為創建對象的開銷, BigDecimal 不適合于大量的數學計算,但設計它的目的是用來精確地表示小數。如果您正在尋找一種能精確表示如貨幣量這樣的數值,則 BigDecimal 可以很好地勝任該任務。
構造 BigDecimal 數
對于 BigDecimal ,有幾個可用的構造函數。其中一個構造函數以雙精度浮點數作為輸入,另一個以整數和換算因子作為輸入,還有一個以小數的 String 表示作為輸入。要小心使用 BigDecimal(double) 構造函數,因為如果不了解它,會在計算過程中產生舍入誤差。請使用基于整數或 String 的構造函數。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Test { public static void main(String[] args) { // 以雙精度浮點數進行構造 BigDecimal bd1 = new BigDecimal( 0.5 ); BigDecimal bd2 = new BigDecimal( 0.1 ); System.out.println(bd1.add(bd2)); // 以String類型進行構造 BigDecimal bd3 = new BigDecimal( "0.5" ); BigDecimal bd4 = new BigDecimal( "0.1" ); System.out.println(bd3.add(bd4)); } } |
輸出結果為:
0.6000000000000000055511151231257827021181583404541015625
0.6
上面代碼分別以
1
2
|
BigDecimal( double val) BigDecimal(String val) |
不同的方式進行構造 BigDecimal 數,輸出的結果是不一樣的。
回到最開始的示例,提供工具類進行精確的浮點數運算,包括加減乘除和四舍五入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
import java.math.BigDecimal; public class ArithUtil { private static final int DEF_DIV_SCALE = 6 ; // 默認除法運算精度 /** * 提供精確的加法運算。 * * @param v1 被加數 * @param v2 加數 * @return 兩個參數的和 */ public static double add( double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2).doubleValue(); } /** * 提供精確的減法運算。 * * @param v1 被減數 * @param v2 減數 * @return 兩個參數的差 */ public static double sub( double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.subtract(b2).doubleValue(); } /** * 提供精確的乘法運算。 * * @param v1 被乘數 * @param v2 乘數 * @return 兩個參數的積 */ public static double mul( double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2).doubleValue(); } /** * 提供(相對)精確的除法運算,當發生除不盡的情況時,精確到 小數點以后10位,以后的數字四舍五入。 * * @param v1 被除數 * @param v2 除數 * @return 兩個參數的商 */ public static double div( double v1, double v2) { return div(v1, v2, DEF_DIV_SCALE); } /** * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale參數指 定精度,以后的數字四舍五入。 * * @param v1 被除數 * @param v2 除數 * @param scale 表示表示需要精確到小數點以后幾位。 * @return 兩個參數的商 */ public static double div( double v1, double v2, int scale) { if (scale < 0 ) { throw new IllegalArgumentException( "The scale must be a positive integer or zero" ); } BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); } /** * 提供精確的小數位四舍五入處理。 * * @param v 需要四舍五入的數字 * @param scale 小數點后保留幾位 * @return 四舍五入后的結果 */ public static double round( double v, int scale) { if (scale < 0 ) { throw new IllegalArgumentException( "The scale must be a positive integer or zero" ); } BigDecimal b = new BigDecimal(Double.toString(v)); BigDecimal one = new BigDecimal( "1" ); return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue(); } } |
結束語:
在 Java 程序中使用浮點數和小數充滿著陷阱。浮點數和小數不象整數一樣“循規蹈矩”,不能假定浮點計算一定產生整型或精確的結果,雖然它們的確“應該”那樣做。最好將浮點運算保留用作計算本來就不精確的數值,譬如測量。如果需要表示定點數(譬如,幾美元和幾美分),則使用 BigDecimal 。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://blog.csdn.net/itmyhome1990/article/details/77852597?utm_source=tuicool&utm_medium=referral