浮點數的基本數據類型不能用
==比較,包裝數據類型不能用equals比較
浮點數的表示
在計算機系統中,浮點數采用 符號+階碼+尾數 進行表示。在Java中,單精度浮點數float類型占32位,它的二進制表示方式為:
- 符號位:1位,0表示正數; 1表示負數
- 指數位:8位,用來表示指數(要加上偏移量)
- 小數位:23位,用來表示小數
實際上計算機中的浮點數表示方法和科學技術法類似,小數的位數決定了浮點數的精度。當一個十進制的小數轉換成二進制時,很有可能無法使用這么多小數位表示它。因此使用浮點數的時候,實際存儲的尾數是被截取或者舍入之后的值。因此使用浮點數進行計算的時候就不得不考慮精度問題,即浮點數無法精確計算。
如何比較浮點數
1. 不能使用==
對於浮點數,我們無法使用==或者包裝類型的equals()來精確比較。例如:
// 對f1執行11次加0.1的操作
float f1 = 0.0f;
for (int i = 0; i < 11; i++) {
f1 += 0.1f;
}
// f2是0.1*11的結果
float f2 = 0.1f * 11;
System.out.println(f1 == f2); // 結果為false
執行上述代碼,會得到二者不相等,同時如果打印f1和f2,會得到如下結果:
f1 = 1.1000001
f2 = 1.1
可以看到,在浮點數的運算過程中,確實出現了精度問題。
2. 規定誤差范圍
盡管無法做到精確比較,但是我們可以確定一個誤差范圍,當小於這個誤差范圍的時候就認為這兩個浮點數相等。例如:
final float THRESHOLD = 0.000001; // 設置最大誤差不超過0.000001
float f1 = 0.0f;
for (int i = 0; i < 11; i++) {
f1 += 0.1f;
}
float f2 = 0.1f * 11;
if (Math.abs(f1 - f2) < THRESHOLD) {
System.out.println("f1 equals f2");
}
3. 使用BigDecimal
BigDecimal是一個不可變的、能夠表示大的十進制整數的對象。注意使用BigDecimal時,要使用參數為String的構造方法,而不要使用參數為double的構造方法,防止產生精度丟失。使用BigDecimal進行運算,使用它的compareTo()方法比較即可。
示例:
private void compareByBigDecimal() {
BigDecimal f1 = new BigDecimal("0.0");
BigDecimal pointOne = new BigDecimal("0.1");
for (int i = 0; i < 11; i++) {
f1 = f1.add(pointOne);
}
BigDecimal f2 = new BigDecimal("0.1");
BigDecimal eleven = new BigDecimal("11");
f2 = f2.multiply(eleven);
System.out.println("f1 = " + f1);
System.out.println("f2 = " + f2);
if (f1.compareTo(f2) == 0) {
System.out.println("f1 and f2 are equal using BigDecimal");
} else {
System.out.println("f1 and f2 are not equal using BigDecimal");
}
}
