Here are clear visual-style breakdowns of how 0.1f, 0.2f, and 0.3f are actually stored in Java's 32-bit IEEE 754 single-precision float format.
Decimal: 0.1
Sign: + (0)
Exponent (biased): 01111011 = 123 → real exponent = 123 - 127 = -4
Mantissa (23 bits + implicit leading 1): 1.10011001100110011001101
Full 32-bit pattern:
S Exponent Mantissa (23 bits)
↓ ↓ ↓
0 01111011 10011001100110011001101
Binary: 0011 1101 1100 1100 1100 1100 1100 1101
Hex: 3D CC CC CD
└───────┬────────┬────────┘
0.1f
Approximate real value: 0.100000001490116119384765625
Decimal: 0.2
Sign: + (0)
Exponent (biased): 01111100 = 124 → real exponent = 124 - 127 = -3
Mantissa (23 bits + implicit 1): 1.10011001100110011001101
Full 32-bit pattern:
S Exponent Mantissa
↓ ↓ ↓
0 01111100 10011001100110011001101
Binary: 0011 1110 0100 1100 1100 1100 1100 1101
Hex: 3E 4C CC CD
└───────┬────────┬────────┘
0.2f
Approximate real value: 0.20000000298023223876953125
Decimal: 0.3
Sign: + (0)
Exponent (biased): 01111101 = 125 → real exponent = 125 - 127 = -2
Mantissa (23 bits + implicit 1): 1.00110011001100110011010
Full 32-bit pattern:
S Exponent Mantissa
↓ ↓ ↓
0 01111101 00110011001100110011010
Binary: 0011 1110 1001 1001 1001 1001 1001 1010
Hex: 3E 99 99 9A
└───────┬────────┬────────┘
0.3f
Approximate real value: 0.29999999701976776123046875
When you add 0.1f + 0.2f in float precision:
- The exact sum before final rounding ≈ 0.30000001192092896
- After rounding back to 23 mantissa bits + proper exponent → it lands exactly on the same bit pattern as 0.3f!
Resulting bit pattern is identical to 0.3f:
0011 1110 1001 1001 1001 1001 1001 1010 → 3E99999A (hex)
That's why in float:
0.1f + 0.2f == 0.3f → true
(while in double it remains false)
Hope these bit-level breakdowns make the floating-point mystery a bit more visual and understandable! 🧩