COMPUTER SCIENCE / NUMBER SYSTEMS

IEEE 754 Floating-Point Converter and Calculator for Float, Double, Half, bfloat16 and FP8

Convert any number to its IEEE 754 bits, or bits back to a number, in double, single, half, bfloat16, FP8 and quadruple precision. See the exact stored value, the rounding error and why it happens.

Convert a number

Decimal input accepts 0.1, -2.5e-7, 1/3, 2^-10, hex floats such as 0x1.8p3, pi, e, inf and nan. Values are converted exactly, digit by digit, with no hidden JavaScript rounding.

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.
value = (−1)sign × 1.fraction₂ × 2exponent − bias

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.

  1. The number is negative, so the sign bit is 1.
  2. 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₂.
  3. Normalise by moving the point four places left: 1.1011101₂ × 2⁴.
  4. Add the bias: 4 + 127 = 131 = 10000011₂.
  5. 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

FormatSign · exponent · fraction bitsBiasDecimal digitsLargest valueSmallest normalMachine epsilon
Half, binary16 (FP16)1 · 5 · 1015≈ 3.365,5046.10 × 10⁻⁵2⁻¹⁰ ≈ 9.77 × 10⁻⁴
bfloat16 (BF16)1 · 8 · 7127≈ 2.43.39 × 10³⁸1.18 × 10⁻³⁸2⁻⁷ ≈ 7.81 × 10⁻³
Single, binary32 (float)1 · 8 · 23127≈ 7.23.40 × 10³⁸1.18 × 10⁻³⁸2⁻²³ ≈ 1.19 × 10⁻⁷
Double, binary64 (double)1 · 11 · 521023≈ 16.01.80 × 10³⁰⁸2.23 × 10⁻³⁰⁸2⁻⁵² ≈ 2.22 × 10⁻¹⁶
Quadruple, binary1281 · 15 · 11216383≈ 34.01.19 × 10⁴⁹³²3.36 × 10⁻⁴⁹³²2⁻¹¹² ≈ 1.93 × 10⁻³⁴
FP8 E5M21 · 5 · 215≈ 0.957,3446.10 × 10⁻⁵2⁻² = 0.25
FP8 E4M3 (E4M3FN)1 · 4 · 37≈ 1.24480.0156252⁻³ = 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 with getUint32(0). Use setFloat64 and getBigUint64 for doubles.
  • C and C++: copy the float into a uint32_t with memcpy, or std::bit_cast in C++20. Casting the pointer breaks the aliasing rules.
  • Java: Float.floatToIntBits(0.1f) and Double.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

ValueSingle precision (hex)Double precision (hex)
10x3F8000000x3FF0000000000000
0.50x3F0000000x3FE0000000000000
−20xC00000000xC000000000000000
0.10x3DCCCCCD0x3FB999999999999A
π0x40490FDB0x400921FB54442D18
Largest finite value0x7F7FFFFF ≈ 3.40 × 10³⁸0x7FEFFFFFFFFFFFFF ≈ 1.80 × 10³⁰⁸
+∞0x7F8000000x7FF0000000000000
Quiet NaN0x7FC000000x7FF8000000000000

Frequently asked questions

What is IEEE 754?

It is the technical standard, first published in 1985 and last revised in 2019, that defines how computers store and round floating-point numbers. It specifies the binary formats, special values such as infinity and NaN, rounding rules and the results of basic operations.

How many digits of precision does a float have?

A 32-bit float has 24 significant bits, about 7 decimal digits. A 64-bit double has 53 bits, about 16 digits. The precision is relative, so very large numbers have large gaps between neighbouring values.

Why is 0.1 + 0.2 not equal to 0.3?

0.1, 0.2 and 0.3 cannot be written exactly in binary, so each is rounded. The rounded 0.1 and 0.2 add up to a value just above the rounded 0.3, which prints as 0.30000000000000004 in double precision.

What is the difference between float and double?

float is single precision: 32 bits, about 7 digits, with a range up to about 3.4 × 10³⁸. double is double precision: 64 bits, about 16 digits, with a range up to about 1.8 × 10³⁰⁸. Use double unless memory or speed matters more than accuracy.

What is bfloat16?

A 16-bit format with float32’s 8-bit exponent but only 7 fraction bits. It covers the same range as a 32-bit float with about 2 to 3 significant digits, which suits machine-learning training.

What is a subnormal number?

A value smaller than the smallest normal number, stored with an exponent field of 0 and no hidden leading 1. Subnormals let values fade gradually toward zero instead of jumping straight to it, at the cost of precision.

What does a hex float such as 0x1.8p3 mean?

The digits before the p are a hexadecimal significand and the number after it is a power of 2. 0x1.8 is 1.5, so 0x1.8p3 = 1.5 × 2³ = 12. The format writes binary values exactly and is printed by %a in C and float.hex() in Python.

How do I see the bits of a float in Python or JavaScript?

In Python, struct.pack('>f', x).hex() returns the single-precision bits in hex. In JavaScript, write the value into a DataView with setFloat32 and read it back with getUint32. Both should match the hexadecimal shown here.

Why is NaN not equal to itself?

IEEE 754 defines every comparison involving NaN as unordered, so NaN == NaN is false. Use a dedicated test such as isnan() or Number.isNaN().

← Number-system calculators