Floating-Point Explorer
see how an IEEE 754 float stores a number, bit by bit
Number0.1→ binary32 (single)
binary32 (single) · 32 bits
- Sign (1)
- Exponent (8)
- Fraction (23)
The bits are written in the last stage of the conversion. Press Next step.
Converting 0.1 → binary32 (single)
- 1. Sign…
- 2. Scale to 1.x…
- 3. Exponent…
- 4. Round…
- 5. Assemble…
step 1 of 6
Convert 0.1 to binary32 (single). Press Next step to walk through it.
Convert 0.1 to binary32 (single). Press Next step to walk through it.
How it works
Type a number or flip individual bits and see exactly how IEEE 754 single and double precision store it: sign, exponent and fraction, rounding error, subnormals, infinities and NaN.
How IEEE 754 stores a number
A binary floating-point number is scientific notation in base 2. Instead of writing 0.15625 as 1.5625 × 10⁻¹, the hardware writes it as 1.01₂ × 2⁻³ and stores the three parts in fixed-width fields:
| Format | Sign | Exponent | Fraction | Total |
|---|---|---|---|---|
| binary16 (half) | 1 bit | 5 bits | 10 bits | 16 bits |
binary32 (single, float) | 1 bit | 8 bits | 23 bits | 32 bits |
binary64 (double, double) | 1 bit | 11 bits | 52 bits | 64 bits |
The sign bit is 0 for positive and 1 for negative. The fraction holds the digits after the binary point. The digit before the point is always 1 for a normal number, so it isn’t stored at all: this “hidden bit” gives binary32 24 bits of precision from a 23-bit field.
The exponent is stored with a bias so that the field is always a plain unsigned number. For binary32 the bias is 127: an exponent of −3 is stored as 124, and 0 is stored as 127. That is why 1.0 in binary32 is 0x3F80_0000: sign 0, exponent field 127 (01111111), fraction 0.
The explorer computes every value exactly, with integer arithmetic, and only uses the platform’s own floating-point numbers to choose short labels.
Normal, subnormal and the special values
Two exponent field values are reserved:
- All zeros means zero or a subnormal number. There is no hidden 1, and the exponent is fixed at its minimum (−126 for binary32). Subnormals fill the gap between zero and the smallest normal number, 1.1754944 × 10⁻³⁸, so that numbers shrink gradually instead of jumping straight to zero. The smallest binary32 subnormal has only the last fraction bit set: about 1.4 × 10⁻⁴⁵.
- All ones means infinity when the fraction is zero, and NaN (not a number) when it isn’t. A NaN whose top fraction bit is set is a quiet NaN; the remaining fraction bits are a payload that hardware and libraries can use to carry information.
Zero has a sign too. +0 and −0 compare as equal, but they are different bit patterns, and dividing 1 by them gives +∞ and −∞.
Converting a decimal, and why rounding happens
Most decimal fractions have no finite binary expansion. 0.1 in binary is 0.000110011001100… with the 1100 repeating forever, exactly as 1/3 repeats in decimal. A format with 24 bits of precision has to stop somewhere, so every conversion follows the same five steps, which the explorer shows one at a time:
- Record the sign and work with the magnitude.
- Scale it into [1, 2): 0.1 = 1.6 × 2⁻⁴.
- Bias the exponent: −4 + 127 = 123.
- Round the significand to the available bits.
- Assemble the three fields.
The default rounding mode is round to nearest, ties to even. The first discarded bit (the guard bit) says whether the rest is above or below half a unit in the last place; the sticky bit says whether anything at all was left beyond it. When the discarded part is exactly half, a tie, the value goes to whichever neighbour has an even last bit. Ties going either way on alternate inputs keep long sums from drifting in one direction.
The result: 0.1 in binary32 is stored as exactly 0.100000001490116119384765625. The explorer shows that full expansion, the error against what you typed, and the same error measured in ULPs.
ULPs and machine epsilon
A ULP (unit in the last place) is the gap between a float and the next one up. It depends on the exponent: the spacing doubles every time the exponent goes up by one. Between 1 and 2, binary32 values are 2⁻²³ apart, about 1.19 × 10⁻⁷. That number is machine epsilon: the gap between 1.0 and the next representable value. For binary64 it is 2⁻⁵², about 2.22 × 10⁻¹⁶.
Because the spacing grows with magnitude, binary32 stores every integer exactly only up to 2²⁴ = 16,777,216. Above that the gap is 2, so 16,777,217 lies exactly halfway between two neighbours and rounds to the even one, 16,777,216. Use Next up and Next down to walk along the representable values and watch the gap change.
Why 0.1 + 0.2 ≠ 0.3
In binary64 neither 0.1 nor 0.2 is exact. The stored values are:
0.1 → 0.1000000000000000055511151231257827021181583404541015625
0.2 → 0.200000000000000011102230246251565404236316680908203125
0.3 → 0.299999999999999988897769753748434595763683319091796875
Their exact sum, 0.3000000000000000166533453693773481063544750213623046875, isn’t representable either, so the addition rounds it to the nearest binary64 value: 0.3000000000000000444089209850062616169452667236328125. That is one ULP above the value stored for 0.3, so the comparison is false. Neither number is wrong: each one is the closest binary64 value to an exact result, and the closest values just don’t line up. When you compare computed floats, compare against a tolerance scaled to the magnitude, not with ==.
Try it
-
0.1 is not 0.1
0.1 is stored as slightly more than 0.1. Look at the rounding stage: which way did it round, and how many ULPs is the error?
-
0.1 in binary64
Step through 0.1 in binary64. The fraction pattern is the same repeating
1100, so why is the error so much smaller? -
16777217 in binary32
Convert 16,777,217 in binary32. The guard bit is 1 and the sticky bit is 0: what does that make it, and which way does it go?
-
16777219: a tie rounds to even
Now try 16,777,219. It is also exactly halfway, but this time it rounds up. Compare the last kept bit with experiment 3.
-
Smallest subnormal
Press Next down twice from the smallest subnormal. The first press reaches +0. Where does the second land, and why does it skip −0?
-
3.5e38 overflows
Step through 3.5 × 10³⁸. At which stage does the conversion give up on a finite result?
Each one opens the matching scenario in the explorer above.
Answer to experiment 3
16,777,217 needs 25 significant bits. The 24 kept bits end in 0 and the discarded part is exactly half a ULP (guard 1, sticky 0), so it is a tie. Ties go to the even neighbour, and the kept significand is already even, so the value rounds down to 16,777,216. In experiment 4 the kept significand ends in 1, so the tie rounds up to 16,777,220.
Where this fits
Floating-point arithmetic runs on a processor’s floating-point unit. The architecture series’ ALU chapter builds the integer ALU from logic gates and explains how it differs from an FPU. This explorer covers what the FPU’s operands look like. It models conversion and the representation itself, not floating-point addition or multiplication, and only the default rounding mode.