BINARY FLOATING-POINT ANATOMY — 32 & 64 BIT
When you write 3.14 or 0.1 in a program, your computer stores it as a pattern of bits. Almost every modern CPU, phone and GPU uses the same pattern, defined by the IEEE 754 standard (first published in 1985 and revised in 2008 and 2019). The visualizer above lets you see that pattern for yourself: type a decimal, paste a hex value or click individual bits, and it shows exactly how the number is stored.
A floating-point number works like scientific notation, but in binary. Instead of 6.02 × 10²³, the computer stores a sign, an exponent and a fraction (called the mantissa or significand):
For a normal number, the value is (−1)sign × 1.mantissa × 2(exponent − bias). The leading 1 is not stored because it is always there, which is how a float gets 24 bits of precision from 23 stored bits (and a double gets 53 from 52).
0.10000000 in binary.10010010000111111011011.0 10000000 10010010000111111011011. Grouped in fours that is 0100 0000 0100 1001 0000 1111 1101 1011, or 0x40490FDB.Twenty-three bits cannot hold every digit of π, so the stored value is really 3.14159274…, not 3.14159265…. That tiny gap is why the tool shows 3.1415927 in 32-bit mode.
In decimal, 1/3 becomes 0.3333… and never ends. In binary, 0.1 has the same problem: it becomes the repeating pattern 0.0001100110011…, so the computer has to cut it off and store a close neighbour instead. Add 0.1 and 0.2 in double precision and you get 0.30000000000000004. This is not a bug in your language. JavaScript, Python, C++ and Java all give the same answer because they all follow IEEE 754. To see it, switch to 64-bit mode, enter 0.1, and look at the repeating 9s in the hex value 0x3FB999999999999A.
Two exponent patterns are reserved. When the exponent is all 0s, the number is zero or subnormal. Subnormals drop the implied leading 1 so values can fade gradually toward zero instead of jumping straight to it. When the exponent is all 1s, the number is infinity (mantissa all 0s) or NaN, short for Not a Number (mantissa not all 0s). Infinity appears on overflow, such as 1e39 stored in a float, and NaN appears from operations like 0 ÷ 0. There are also two zeros, +0 and −0. They compare equal, but 1 ÷ −0 gives −∞, and NaN is never equal to anything, not even itself.
| Value | Float (32-bit) hex | Double (64-bit) hex |
|---|---|---|
| +0 | 0x00000000 | 0x0000000000000000 |
| −0 | 0x80000000 | 0x8000000000000000 |
| +∞ | 0x7F800000 | 0x7FF0000000000000 |
| −∞ | 0xFF800000 | 0xFFF0000000000000 |
| NaN (quiet) | 0x7FC00000 | 0x7FF8000000000000 |
| Smallest subnormal | 0x00000001 (≈ 1.4 × 10⁻⁴⁵) | 0x0000000000000001 (≈ 4.9 × 10⁻³²⁴) |
| Smallest normal | 0x00800000 (≈ 1.18 × 10⁻³⁸) | 0x0010000000000000 (≈ 2.23 × 10⁻³⁰⁸) |
| Largest finite | 0x7F7FFFFF (≈ 3.40 × 10³⁸) | 0x7FEFFFFFFFFFFFFF (≈ 1.80 × 10³⁰⁸) |
| Property | Float (32-bit) | Double (64-bit) |
|---|---|---|
| Significant bits | 24 | 53 |
| Decimal digits | about 7 | about 15 to 16 |
| Machine epsilon | 2⁻²³ ≈ 1.19 × 10⁻⁷ | 2⁻⁵² ≈ 2.22 × 10⁻¹⁶ |
| Integers exact up to | 2²⁴ = 16,777,216 | 2⁵³ = 9,007,199,254,740,992 |
Past those integer limits the format can no longer count by ones. Enter 16777217 in 32-bit mode and it rounds to 16777216.
isnan instead.0.1 is a double and 0.1f is a float, so 0.1f == 0.1 is false.