Java float(單精度)佔 4 位元組(32 位元),double(雙精度)佔 8 位元組(64 位元),均遵循 IEEE 754 標準。以 float 為例,位元配置如下:
數值公式:(-1)^sign × 1.mantissa × 2^(exponent-127)
十進位 0.1 在二進位為無限循環小數:0.0001100110011...。以下程式驗證 float 實際儲存的位元模式:
public class FloatAnalysis {
public static void main(String[] args) {
float f = 0.1f;
int bits = Float.floatToIntBits(f);
System.out.println("0.1f 二進位: " + Integer.toBinaryString(bits));
// 輸出: 111101110011001100110011001101
// 手動重建驗證
int sign = 0;
int exponent = 123; // 123 - 127 = -4
int mantissa = 0x4CCCCD; // 23 位尾數
int reconstructed = (sign << 31) | (exponent << 23) | mantissa;
System.out.println("重建結果: " + Integer.toBinaryString(reconstructed));
// 兩者完全一致,證明 0.1 為近似值
}
}
0.5 = 2^-1 = 1.0 × 2^-1,二進位科學標記法尾數為 1.0(小數點後全 0),指數 -1 + 127 = 126,完美符合 IEEE 754 格式,無任何捨入誤差。
| 場景 | 問題 | 解決方案 |
|---|---|---|
| 金融計算 | 0.1 + 0.2 ≠ 0.3 | 使用 BigDecimal,指定縮放位數與捨入模式 |
| 比較運算 | 直接 == 比較失敗 | 設定容許誤差:Math.abs(a-b) < 1e-6 |
| 大量累加 | 誤差累積放大 | Kahan Summation 演算法或 BigDecimal |
| 序列化傳輸 | 跨平台精度差異 | 協定層面約定定點數或字串傳輸 |