How to use the IEEE 754 converter
Type a decimal number and pick a format to see exactly how a computer stores it. You get:
- the stored value, the bits and the hexadecimal pattern
- the exact decimal value of those bits and the rounding error
- the gap to the next float, and the next floats up and down
- the format’s precision and range, and a step-by-step conversion
To go the other way, choose a hexadecimal or binary bit pattern as the input, or click any bit in the grid to flip it and watch the value change. A table breaks the bits into sign, exponent and fraction and says what each one means. The results also give:
- the C-style hex float literal, such as 0x1.99999ap-4 (you can also type one as input)
- the same bits read as a signed and unsigned integer
- the bytes in big- and little-endian order, for matching a memory dump
Copy link to this result saves the current numbers in a link you can share or bookmark. The Arithmetic tab adds, subtracts, multiplies or divides two numbers inside the chosen format, or performs a fused multiply-add. It walks through the same steps a processor takes, so you can see where results such as 0.1 + 0.2 = 0.30000000000000004 come from.
The result also reports the five IEEE 754 exception flags: invalid operation, division by zero, overflow, underflow and inexact. A fused multiply-add computes a × b + c with one final rounding, which can preserve a small result that would disappear if the multiplication were rounded before the addition.
All the arithmetic is done with exact whole-number maths, not with your browser’s own floating point. The exact values and rounding are therefore right for every format, including 128-bit quadruple precision, and for custom widths you define yourself.
How IEEE 754 stores a number
IEEE 754 is the standard almost every processor uses for real numbers. It stores a number in binary scientific notation, split into three fields:
- Sign: one bit, 0 for positive and 1 for negative.
- Exponent: the power of 2, stored with a fixed bias added so that it is never negative. The bias is 127 for single precision and 1023 for double.
- Fraction (mantissa): the bits after the binary point. Normal numbers always start with 1., so that leading 1 is not stored. It is the “hidden bit”, and it gives one extra bit of precision for free.
Take 0.1 in single precision. In binary it is 0.000110011001100…, a pattern that repeats for ever. Normalised, it is 1.10011001100…₂ × 2⁻⁴, so the exponent field is −4 + 127 = 123. The first 23 fraction bits are kept and the rest rounded, giving 0 01111011 10011001100110011001101, or 0x3DCCCCCD. The stored value is 0.100000001490116119384765625, slightly more than 0.1.
Converting by hand: two worked examples
Decimal to single precision: −27.625.
- The number is negative, so the sign bit is 1.
- Convert the whole part and the fraction separately. 27 = 11011₂. For 0.625, keep doubling and take the whole-number digit each time: 1.25 → 1, 0.5 → 0, 1.0 → 1. That gives 0.101₂, so 27.625 = 11011.101₂.
- Normalise by moving the point four places left: 1.1011101₂ × 2⁴.
- Add the bias: 4 + 127 = 131 = 10000011₂.
- The fraction is the bits after the point, padded to 23 bits: 10111010000000000000000. Nothing is cut off, so no rounding is needed.
The result is 1 10000011 10111010000000000000000, or 0xC1DD0000.
Single precision to decimal: 0x42340000. In binary this is 0 10000100 01101000000000000000000. The sign is positive. The exponent field is 132, and 132 − 127 = 5. Putting back the hidden bit gives 1.01101₂. Moving the point five places right gives 101101₂, which is 32 + 8 + 4 + 1 = 45. Load either example into the calculator to see every step.
Floating-point formats compared
| Format | Sign · exponent · fraction bits | Bias | Decimal digits | Largest value | Smallest normal | Machine epsilon |
|---|---|---|---|---|---|---|
| Half, binary16 (FP16) | 1 · 5 · 10 | 15 | ≈ 3.3 | 65,504 | 6.10 × 10⁻⁵ | 2⁻¹⁰ ≈ 9.77 × 10⁻⁴ |
| bfloat16 (BF16) | 1 · 8 · 7 | 127 | ≈ 2.4 | 3.39 × 10³⁸ | 1.18 × 10⁻³⁸ | 2⁻⁷ ≈ 7.81 × 10⁻³ |
| Single, binary32 (float) | 1 · 8 · 23 | 127 | ≈ 7.2 | 3.40 × 10³⁸ | 1.18 × 10⁻³⁸ | 2⁻²³ ≈ 1.19 × 10⁻⁷ |
| Double, binary64 (double) | 1 · 11 · 52 | 1023 | ≈ 16.0 | 1.80 × 10³⁰⁸ | 2.23 × 10⁻³⁰⁸ | 2⁻⁵² ≈ 2.22 × 10⁻¹⁶ |
| Quadruple, binary128 | 1 · 15 · 112 | 16383 | ≈ 34.0 | 1.19 × 10⁴⁹³² | 3.36 × 10⁻⁴⁹³² | 2⁻¹¹² ≈ 1.93 × 10⁻³⁴ |
| FP8 E5M2 | 1 · 5 · 2 | 15 | ≈ 0.9 | 57,344 | 6.10 × 10⁻⁵ | 2⁻² = 0.25 |
| FP8 E4M3 (E4M3FN) | 1 · 4 · 3 | 7 | ≈ 1.2 | 448 | 0.015625 | 2⁻³ = 0.125 |
More exponent bits give more range, and more fraction bits give more precision. bfloat16 keeps the full range of a 32-bit float but only about two or three significant digits. FP16 has more precision but overflows above 65,504.
Floating-point precision explained
A float has a fixed number of significant binary digits, not decimal places. Its precision is therefore relative. Every number in a format has about the same number of significant digits: roughly 7 for single precision and 16 for double. The absolute gap between neighbouring floats, called one ULP (unit in the last place), grows with the size of the number. In single precision the gap is about 0.00000012 near 1, but 64 near one billion. Above 2²⁴ = 16,777,216, a float can no longer store every whole number, so 16,777,217 becomes 16,777,216. Doubles hold every integer up to 2⁵³ = 9,007,199,254,740,992, which is why JavaScript’s largest “safe” integer is 2⁵³ − 1.
Machine epsilon is the gap between 1 and the next float up: 2⁻²³ for single and 2⁻⁵² for double. Rounding to nearest makes any single conversion or operation accurate to within half of that, relative to the result. Errors build up, though, over long calculations. They grow quickly when you subtract two nearly equal numbers, because the leading digits cancel and only the rounding noise is left. This is called catastrophic cancellation.
When printing, about 9 significant digits are enough to recover any single-precision value exactly, and 17 for double. In the other direction, 6 and 15 digits respectively always survive a trip into the format and back.
Why 0.1 + 0.2 is not 0.3
A decimal fraction ends in binary only if its denominator is a power of 2. So 0.5 and 0.375 are exact, but 0.1, 0.2 and 0.3 are not, and each is rounded to the nearest double:
- 0.1 is stored as 0.1000000000000000055511151231257827…
- 0.2 is stored as 0.2000000000000000111022302462515654…
- 0.3 is stored as 0.2999999999999999888977697537484345…
The exact sum of the first two is 0.3000000000000000166533453693773481…. That falls exactly halfway between the double used for 0.3 and the next double up. Ties go to the neighbour whose last bit is even, which here is the one above, printed as 0.30000000000000004. The two results differ in the last bit, so 0.1 + 0.2 == 0.3 is false. Nothing is broken: each step was rounded correctly, and the small input errors happened to point the same way.
How floating-point addition and multiplication work
To add two floats, the processor first lines up their binary points. It shifts the significand of the smaller number right until both share the larger exponent. Next it adds the significands, moves the point back so a single 1 leads, and rounds to the format’s width. Bits shifted past the end of the smaller number are lost. That is why 1e16 + 1 is still 1e16 in double precision: the 1 needs to move 53 places right and falls off. Multiplication is simpler. Multiply the significands, add the exponents, combine the signs, then normalise and round.
The precision of the format changes the outcome. In single precision, 0.1 + 0.2 does equal 0.3, because both round to the same 32-bit pattern, 0x3E99999A. In double precision they do not. The Arithmetic tab shows the aligned binary digits for each case.
Zero, subnormals, infinity and NaN
- Signed zero. All exponent and fraction bits are 0. +0 and −0 compare equal, but 1 ÷ −0 gives −∞.
- Subnormal (denormal) numbers. The exponent field is 0 but the fraction is not. They have no hidden 1 and fill the gap between zero and the smallest normal number with evenly spaced values, losing precision as they shrink. This “gradual underflow” means x − y is zero only when x equals y. The smallest single-precision subnormal is about 1.4 × 10⁻⁴⁵.
- Infinity. All exponent bits are 1 and the fraction is 0. It is the result of overflow or of dividing a non-zero number by zero.
- NaN (not a number). All exponent bits are 1 and the fraction is not zero. It is produced by 0 ÷ 0, ∞ − ∞ or the square root of a negative number. NaN is not equal to anything, not even itself, so test for it with a function such as
isnan().
FP8 E4M3 is an exception: it has no infinities, and it uses those bit patterns to reach 448 instead of 240.
Rounding modes
By default, IEEE 754 rounds to the nearest representable value. When a value is exactly halfway, it chooses the one whose last bit is 0 (“ties to even”). This avoids the slow upward drift that always rounding halves up would cause over millions of operations. The standard also defines rounding toward zero, toward +∞ and toward −∞. These are used for truncation, and in interval arithmetic to get guaranteed lower and upper bounds. All five modes are available above, so you can see how each one changes the last bit.
Hex floats, raw integers and byte order
Hexadecimal floating-point literals write the significand in hex and the power of 2 after a p. So 0x1.8p3 means 1.5 × 2³ = 12, and single-precision 0.1 is 0x1.99999ap-4. C and C++ print this form with %a, Python with float.hex(), and Java with Double.toHexString(). It is exact, unlike a rounded decimal, which makes it useful for test data. Don’t confuse it with the bit pattern 0x3DCCCCCD, which is the 32 stored bits written in hex.
Converting is not the same as reinterpreting. Casting 3.7 to an integer gives 3, the same number with the fraction dropped. Reading the same 32 bits as an integer gives 1,080,872,141 instead. Graphics code, hashing functions and file parsers often need this raw view.
Byte order decides how those bits sit in memory. Most desktop and phone processors are little-endian and store the least significant byte first. Single-precision 0.1 then appears in a hex dump as CD CC CC 3D. Network protocols and many file formats use big-endian order, 3D CC CC CD.
bfloat16, FP16 and FP8 in machine learning
Neural networks tolerate small errors, so they are often trained and run in 16-bit or 8-bit formats to save memory and speed up the maths. bfloat16 is popular for training because it has the same 8-bit exponent as float32. Large and tiny values rarely overflow or vanish, and converting between the two just drops or adds 16 fraction bits. FP16 is more precise, but its narrow range often needs loss scaling to stop small gradients turning into zero. FP8 comes in two flavours. E4M3 has more precision and is commonly used for weights and activations. E5M2 has more range and is often used for gradients. Comparing the formats side by side in the calculator shows how much each one rounds a given number.
Where this converter helps
- Debugging: decoding a hex value from a memory dump, network packet, file format or register.
- Testing and numerical code: checking whether a value is exact, finding the next float up or down, and choosing sensible tolerances for comparisons.
- Embedded and graphics work: half-precision textures and sensor data, and checking what a 16-bit format can represent.
- Machine learning: seeing what bfloat16 or FP8 does to weights, learning rates and small gradients.
- Coursework: computer architecture and numerical methods exercises, with every conversion step shown.
Getting the bits in your own code
- Python:
struct.pack('>f', 0.1).hex()gives '3dcccccd'.(0.1).hex()gives the hex float of the double. - JavaScript: write the number with
new DataView(new ArrayBuffer(4)).setFloat32(0, 0.1), then read it back withgetUint32(0). UsesetFloat64andgetBigUint64for doubles. - C and C++: copy the float into a
uint32_twithmemcpy, orstd::bit_castin C++20. Casting the pointer breaks the aliasing rules. - Java:
Float.floatToIntBits(0.1f)andDouble.doubleToLongBits(0.1).
Compare the output with this calculator to check a parser, a network message or a test case.
Common floating-point pitfalls
- Comparing with ==. Check whether |a − b| is within a small tolerance, scaled to the size of the numbers.
- Using floats for money. 0.10 cannot be stored exactly. Use whole cents or a decimal type instead.
- Adding a tiny number to a huge one. In double precision, 1e16 + 1 is still 1e16. When summing many values, add the small ones first or use compensated (Kahan) summation.
- Assuming more digits than the format has. Printing 20 digits of a float shows the binary value, not extra accuracy.
- Casting large integers to float. IDs and timestamps above 2²⁴ (float) or 2⁵³ (double) lose their last digits.
Common values and their bit patterns
| Value | Single precision (hex) | Double precision (hex) |
|---|---|---|
| 1 | 0x3F800000 | 0x3FF0000000000000 |
| 0.5 | 0x3F000000 | 0x3FE0000000000000 |
| −2 | 0xC0000000 | 0xC000000000000000 |
| 0.1 | 0x3DCCCCCD | 0x3FB999999999999A |
| π | 0x40490FDB | 0x400921FB54442D18 |
| Largest finite value | 0x7F7FFFFF ≈ 3.40 × 10³⁸ | 0x7FEFFFFFFFFFFFFF ≈ 1.80 × 10³⁰⁸ |
| +∞ | 0x7F800000 | 0x7FF0000000000000 |
| Quiet NaN | 0x7FC00000 | 0x7FF8000000000000 |