Java float 佔 4 位元組 (32 bits),遵循 IEEE 754 單精度浮點數標準。理解其位元佈局、特殊值表示、精度限制與十六進制互轉,對於網路通訊協定解析、嵌入式資料交換、高效能數值計算、二進制檔案讀寫至關重要。本文從位元層面深度剖析。
31 30-23 22-0 ┌──┬───────────┬─────────────────────┐ │ S │ Exponent │ Mantissa (Fraction) │ └──┴───────────┴─────────────────────┘ 1 bit 8 bits 23 bits
正規化數值 (Exponent ≠ 0 且 ≠ 255):
Value = (-1)^S × 1.Mantissa × 2^(Exponent - 127)
非正規化數值 (Exponent = 0, Mantissa ≠ 0):
Value = (-1)^S × 0.Mantissa × 2^(-126)
| 類別 | Exponent | Mantissa | 十六進制 | 十進制 |
|---|---|---|---|---|
| 正零 | 0 | 0 | 0x00000000 | +0.0 |
| 負零 | 0 | 0 | 0x80000000 | -0.0 |
| 正無窮大 | 255 (全1) | 0 | 0x7F800000 | +Infinity |
| 負無窮大 | 255 | 0 | 0xFF800000 | -Infinity |
| NaN (非數值) | 255 | ≠0 | 0x7FC00000~ | NaN |
| 常數 | 十六進制 | 近似十進制值 | 說明 |
|---|---|---|---|
| Float.MAX_VALUE | 0x7F7FFFFF | 3.4028235E38 | 最大有限正數 (2-2^-23)×2^127 |
| Float.MIN_NORMAL | 0x00800000 | 1.17549435E-38 | 最小正規化正數 2^-126 |
| Float.MIN_VALUE | 0x00000001 | 1.4E-45 | 最小非正規化正數 2^-149 |
public class FloatPrecisionDemo {
public static void main(String[] args) {
// 1. 7-8 位有效數字精度
float f1 = 12345678.0f; // 實際儲存 1.2345678E7
float f2 = 12345679.0f; // 與 f1 相同!精度遺失
System.out.println(f1 == f2); // true
// 2. 經典 0.1 無法精確表示
float sum = 0.0f;
for (int i = 0; i < 10; i++) sum += 0.1f;
System.out.println(sum); // 1.0000001 ≠ 1.0
// 3. 大數吃小數
float big = 1e8f;
float small = 1.0f;
System.out.println(big + small == big); // true,1.0 被吞沒
}
}
Java 提供 Float.floatToIntBits() 與 Float.intBitsToFloat() 進行位元級無損轉換,不經過數值語意解釋。
public static String floatToHex(float f) {
int bits = Float.floatToIntBits(f); // 取得 IEEE 754 位元模式
return "0x" + Integer.toHexString(bits).toUpperCase();
}
// 測試
float f = 0.15490197f;
System.out.println(floatToHex(f)); // 輸出: 0x3E1E9E9F
public static float hexToFloat(String hex) {
// 移除可選前綴 0x/0X
String clean = hex.startsWith("0x") || hex.startsWith("0X") ? hex.substring(2) : hex;
int bits = Integer.parseUnsignedInt(clean, 16); // 解析無符號整數
return Float.intBitsToFloat(bits); // 位元模式直接轉 float
}
// 測試
String hex = "3E1E9E9F";
float f = hexToFloat(hex);
System.out.println(f); // 輸出: 0.15490197
// 接收 4 位元組: 3E 1E 9E 9F
byte[] bytes = {(byte)0x3E, (byte)0x1E, (byte)0x9E, (byte)0x9F};
int bits = ByteBuffer.wrap(bytes).getInt(); // 大端序
float value = Float.intBitsToFloat(bits);
// 寫入
try (DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.bin"))) {
dos.writeFloat(3.14159f); // 自動轉 IEEE 754 位元序
}
// 讀取
try (DataInputStream dis = new DataInputStream(new FileInputStream("data.bin"))) {
float pi = dis.readFloat();
}
// MySQL: CREATE TABLE sensor (id INT, value BINARY(4)); // 寫入 String hex = floatToHex(25.6f).substring(2); // 移除 0x String sql = "INSERT INTO sensor VALUES (1, UNHEX(?))"; // 讀取 String sql = "SELECT HEX(value) FROM sensor WHERE id=1"; float val = hexToFloat(resultSet.getString(1));
Float.toString() / Float.parseFloat() 做二進制轉換 → 會經過十進制語意,失去位元精確性ByteBuffer.order(ByteOrder.BIG_ENDIAN)BigDecimal 或 long (分為單位)Math.abs(a-b) < epsilon 或 Float.compare()掌握 float 的 IEEE 754 位元結構,能讓你在底層資料交換、效能關鍵路徑、異常數值診斷時遊刃有餘。記住兩個核心方法:Float.floatToIntBits() 與 Float.intBitsToFloat(),它們是 Java 浮點數位元世界的雙向傳送門。