Chris Collins

Tools · numbers

Floating-point inspector

See exactly how float64, float32, float16, bfloat16, TF32, the FP8, FP6, and FP4 formats used for AI, and the E8M0 scale store a number — and how block-scaled formats (OCP MX, NVIDIA NVFP4, NF4) build a tensor from tiny elements and shared scales.

Added · updated 14 October 2026

How to use it

Three tabs: Single value takes one number apart in any format; Sums and drift adds 0.1 over and over as a float, as an exact decimal and as integer tenths, and sums one list in several orders; Block-scaled shows how the low-precision formats used for AI store a whole vector with shared scale factors.

Single value

Type a decimal (0.1, -2.5e-8, NaN, Infinity) or raw bits (0x3dcccccd, 0b0_01111011_…) and pick a format.

  • The bits are coloured by field — sign, exponent, mantissa. Click any bit to flip it.

  • Exact decimal value is the number the bits really hold, with every digit; rounding error is how far that is from what you typed.

  • Neighbours are the next representable values up and down, and the ULP (the gap between adjacent values at this magnitude). Alt+↑ and Alt+↓ step through them.

  • This format lists the bias, the largest and smallest values, how Infinity and NaN are encoded (if at all), negative zero, and what happens on overflow.

  • For formats of 8 bits or fewer, All codes lists every bit pattern with its value and draws the positive values on a number line — click one to inspect it.

  • The format ranges table compares every format.

  • The Magnitude slider jumps through 10−324 … 10308: watch the gap between neighbours (the ULP) grow with the number, the subnormals appear below 2.2 × 10−308, and the last values before overflow.

Conversions round to nearest, ties to even, computed exactly. For formats that have no Infinity, the saturate option chooses between the two overflow behaviours of the OCP FP8 specification: SAT clamps to ±max, OVF gives NaN.

The formats

Format Bits Notes

float64, float32, float16

64, 32, 16

IEEE 754 binary formats.

bfloat16

16

float32’s 8-bit exponent with a 7-bit mantissa: float32’s range, about 2–3 significant digits.

TF32

19

NVIDIA Tensor Core input format: float32’s exponent and float16’s 10-bit mantissa, computed from float32 registers.

FP8 E4M3 (OCP)

8

Bias 7. No Infinity; the only NaN is S.1111.111, which lets S.1111.000–110 be values — up to 448.

FP8 E5M2 (OCP)

8

Bias 15, IEEE-style Infinity and NaN, up to 57,344. Wider range, less precision than E4M3.

FP8 E4M3FNUZ, E5M2FNUZ

8

"Finite, NaN, unsigned zero" variants (used by AMD and Graphcore): bias one higher (8 and 16), no Infinity, no negative zero; 0x80 is the single NaN. Maximums 240 and 57,344.

FP6 E2M3, E3M2

6

OCP MX element types, no Infinity or NaN, always saturate. Maximums 7.5 and 28.

FP4 E2M1

4

±{0, 0.5, 1, 1.5, 2, 3, 4, 6}. The element type of MXFP4 and NVFP4.

E8M0

8

An unsigned exponent with no mantissa: the value is 2^(E−127), from 2^−127 to 2^127; 0xFF is NaN; there is no zero. The shared scale of the MX formats.

Sums and drift

Add the same number again and again. Type a decimal (default 0.1), how many times to add it (1 to 10,000,000; type it, drag the log-scale slider, or press a Try button) and float64 or float32. The table shows the total four ways:

  • the float as Python prints it (repr: the shortest digits that read back as the same float; for float32, the shortest digits as NumPy prints them), with its error in absolute terms and in ulps;

  • the same float to 17 significant digits, and the exact value the bits hold;

  • Decimal: exact decimal arithmetic, printed as Python’s decimal.Decimal prints it, trailing zero included (Decimal('100.0'));

  • integer tenths (or hundredths, …, whatever the addend’s last decimal place is): count the units as an integer and divide once at the end.

The drift chart plots the float total minus the exact total after every addition. It is exact to plotting accuracy: each addition’s rounding error is recovered with an error-free TwoSum. For long runs each pixel column shows the range within that slice of the run. The Decimal and integer-tenths totals are the dashed line at 0. The drift is not n times the error in the stored 0.1: every addition rounds again, and the size of that rounding (the ulp) doubles each time the total passes a power of two, so the line bends at 0.125, 0.25, … and can change sign.

Order matters. One list of numbers (mixed sizes and signs, uniform in [0, 1), or tenths; seeded, so a link reproduces it) is summed forward, reversed, shuffled, smallest first, largest first, and with Kahan’s compensated summation, and compared with the exact sum rounded once (what Python’s math.fsum returns), computed with big integers. Floating-point addition is commutative but not associative, so the totals differ by a few ulps.

Block-scaled formats

A 4-bit number can only hold 15 or 16 distinct values, so on its own it is useless for real data. Block-scaled formats give each small block of consecutive values a shared scale; each element then only has to describe its value relative to the block’s largest. Some formats add a second, coarser level of scaling above the blocks. Paste a vector or generate one (Gaussian, uniform, Laplace, or Gaussian with 1% outliers, from a fixed seed), choose a format, and the tool shows the hierarchy — tensor, blocks, elements — with the bits of every scale and element, the decoded values, and the error of each element (coloured from green to red), each block, and the whole vector (MSE, largest error, and SQNR, the signal-to-quantization-noise ratio). Bits per element include the scales. All formats on this vector compares every format on the same data, with SQNR plotted against bits per element.

Format Block Element Scales Bits / element

MXFP8 (E4M3 or E5M2)

32

FP8

E8M0 per block

8.25

MXFP6 (E2M3 or E3M2)

32

FP6

E8M0 per block

6.25

MXFP4

32

E2M1

E8M0 per block

4.25

MXINT8

32

INT8 with an implicit 2^−6

E8M0 per block

8.25

NVFP4

16

E2M1

FP8 E4M3 per block, FP32 per tensor

4.5 + 32/N

NF4

64

4-bit NormalFloat index

FP32 absmax per block

4.5

NF4 + double quantization

64

NF4

FP8 absmax per block, FP32 per 256 blocks, FP32 mean

≈ 4.127

INT4, group 128

128

integer −8 … 7

FP16 scale (amax / 7) per group

4.125

Block floating point (baseline)

16

8-bit integer

8-bit shared exponent

8.5

OCP Microscaling (MX)

The scale is a power of two: X is the largest power of two not above the block’s absolute maximum, divided by the largest power of two the element type can hold (2^8 for E4M3, 2^15 for E5M2, 2^2 for E2M3 and E2M1, 2^4 for E3M2, 2^0 for INT8). Each element is V/X rounded to the element type, ties to even, with values beyond its range clamped to ±max.

Worked example (MXFP4): a block whose largest value is 10. ⌊log₂ 10⌋ = 3 and E2M1’s largest power of two is 2^2, so X = 2^(3−2) = 2 (E8M0 code 128). Then 10/2 = 5 lies exactly between the E2M1 values 4 and 6 and rounds to the even code, 4: the stored 10 comes back as 8. A value of 2.5 becomes 1.25, which rounds to 1 and decodes as 2.

The specification leaves some cases to the implementation; here an all-zero block gets the smallest scale (2^−127), a block containing NaN or ±Infinity gets the NaN scale (so all of its values read as NaN), and the shared exponent is clamped to E8M0’s range — as the reference implementation does.

NVIDIA NVFP4

NVFP4 uses smaller blocks (16) and a more precise block scale: an FP8 E4M3 number, not just a power of two. Because E4M3 only reaches 448, a second, per-tensor FP32 scale first moves the whole tensor into range. With amax the tensor’s largest magnitude, the global encode scale is 6 · 448 / amax (6 and 448 are the largest E2M1 and E4M3 values) and its inverse is stored as FP32. Each block’s decode scale amax_b / 6 is multiplied by the global encode scale and rounded to E4M3; the elements are the inputs times the block’s effective encode scale, rounded to E2M1.

Worked example: two blocks, one with largest value 6 and one with 1.5. The tensor amax is 6, so the global decode scale is 1/448. The first block’s scale is e4m3(1 · 448) = 448; the second’s is e4m3(0.25 · 448) = 112. In the second block 1.5 is stored as 1.5 · 4 = 6, and 0.3 as 1.2 → 1, which decodes as 1 · 112 / 448 = 0.25.

NF4 and double quantization

NF4 (from QLoRA) scales each block of 64 values by its absolute maximum, then stores each value as the index of the nearest of 16 fixed levels placed at quantiles of a normal distribution, from −1 to 1 with an exact zero. FP32 block constants cost 32/64 = 0.5 bits per value. Double quantization quantizes those constants too: their mean is subtracted (and kept as one FP32 number), then they are stored as 8-bit floats in groups of 256 with an FP32 scale per group — 8/64 + 32/(64·256) ≈ 0.127 bits per value instead of 0.5. The QLoRA paper specifies "8-bit floats"; this tool uses FP8 E4M3, while bitsandbytes uses its own 8-bit dynamic map, so its second-level error differs slightly.

INT4 with group scales

The integer layout used by GPTQ- and AWQ-style weight quantization: groups of 128 values share an FP16 scale, amax / 7, and each value is the nearest integer from −8 to 7 (ties to even) — 4
16/128 = 4.125 bits per value. This is the symmetric variant; GPTQ and AWQ often also store a 4-bit zero point per group, which shifts the steps but not their uniform spacing.

One outlier: MXFP4 vs NVFP4 vs INT4 g128 vs NF4

Real activations and weights contain a few values far larger than the rest. The One outlier panel replaces one element of your vector (at, counting from 0) by outlier × the vector’s RMS and quantizes it in the four 4-bit formats. For each it shows the RMS error of the other values of the outlier’s block before and after (bars: blue before, red after), the same over the whole vector, and the outlier’s own error. Every block takes its scale from its largest value, so the outlier stretches its own block’s scale and its neighbours collapse onto the few codes near zero: NVFP4’s 16-value blocks limit the damage to 15 neighbours, INT4’s 128-value groups spread it over 127 with uniform steps, and MXFP4’s power-of-two scale cannot represent the outlier itself closely (it lands on the nearest E2M1 step, up to about 20% off).

Sources

Limits

  • Decimal totals are exact here; Python’s Decimal rounds to 28 significant digits by default, so for a total longer than that (more than about 1026 tenths) Python would round and this tool would not.

  • The drift is computed for float64 and float32 only; the other formats are on the Single value tab.

  • Up to 10,000,000 additions and 100,000 numbers in the order list.

Companion to Numeric formats and quantization (part II) of _AI Acceleration: From Transistors to Trillion-Parameter Models: the precision ladder, block (micro-)scaling, NVFP4 decoding, and INT8/INT4.

Companion to Fractions inside a computer: why 0.1 is not 0.1 (chapter 2), Floating point: how real numbers are stored (chapter 32) and the floating-point mode of the "Laws as tiles" lab in chapter 1 of Mathematics, Reconnected.

Sharing

Share link copies a URL that opens this tool exactly as you have it: every tab’s inputs, with the current tab selected. Opening such a link replaces the inputs this browser had saved for the tool.

Linking to an example

Links can be written by hand. Add the tab after #: single, sum or block.

Parameter Meaning Example

v

The value on the Single value tab: a decimal, NaN, Infinity, or raw bits 0x… / 0b…

v=0.1

fmt

Its format: f64, f32 (the default), f16, bf16, tf32, e4m3, e5m2, e4m3fnuz, e5m2fnuz, e2m3, e3m2, e2m1, e8m0

fmt=f64

sat

Saturate on overflow (1 or true)

sat=1

add

The number added again and again (Sums tab)

add=0.1

n

How many times

n=1000

prec

64 (float64, the default) or 32 (float32)

prec=32

list

The list summed in different orders: mixed, uniform or tenths

list=mixed

len

How many numbers in that list

len=1000

seed

Its random seed

seed=2

bs, kind, bn, bseed, scale, vec

Block-scaled tab: format id (mxfp4, nvfp4, nf4, nf4dq, int4g128, mxfp8e4m3, …), generator (normal, uniform, laplace, outliers), length (32 to 1024), seed, scale, or the vector itself

bs=mxfp4&kind=normal

outlier

Block-scaled tab, One outlier panel: the outlier’s size in multiples of the vector’s RMS

outlier=20

at

which element becomes the outlier (from 0)

at=5

example

One of the presets below; parameters given with it override the preset’s

example=ch02-drift

In a URL + means a space, so write a plus sign as %2B (v=1e%2B300). A value such as 1e+300 typed straight into the address bar also works: the tool reads 1e 300 back as 1e+300.

Presets:

example= Shows

ch02-point-one

0.1 as a double: the stored binary value, its bits, its neighbours and the error (open)

ch02-point-two

0.2 as a double, stored slightly above 0.2 (open)

ch02-point-three

0.3 as a double, stored slightly below 0.3, which is why 0.1 + 0.2 ≠ 0.3 (open)

ch02-quarter

0.25, stored exactly because its denominator is a power of 2 (open)

ch02-sum-tenths

sum([0.1] * 10) is 0.9999999999999999, while Decimal gives 1.0 and integer tenths 10 (open)

ch02-drift

The lab: 0.1 added 1,000 times, the float drifting from n/10 while Decimal and tenths stay exact (open)

ch02-drift-float32

The same in float32: 1,000 additions give 99.99905 (open)

ch01-sum-order

1,000 floats summed forward, reversed and shuffled give different totals (open)

ch32-float-explorer

0.1 in float64 with its ulp; drag the Magnitude slider from 10−324 to 10308 (open)

ch32-subnormal

The smallest subnormal double, 5 × 10−324 (open)

p02-e2m1-1110

FP4 E2M1 code 1110 (sign 1, exponent 11, mantissa 0) decodes to −4; all 16 codes are listed below it (open)

p02-tf32

TF32 keeps FP32’s 8-bit exponent and a 10-bit mantissa: 19 bits used, the low 13 bits of the 32-bit register ignored (open)

p02-e4m3-max

FP8 E4M3’s largest value, 448; the Format ranges table sets it beside E5M2’s 57,344 (open)

p02-e5m2-max

FP8 E5M2’s largest value, 57,344 — range bought with a mantissa bit (open)

p02-mxfp4-block

One MXFP4 block: 32 E2M1 elements and one E8M0 scale, 136 bits (17 bytes) against 1,024 bits in FP32 — 4.25 bits per value (open)

p02-nvfp4-bits

NVFP4 on 1,024 values: E2M1, an E4M3 scale per 16, and one FP32 tensor scale — 4.53 bits per value, the "≈ 4.5" (open)

p02-outliers

One outlier of 20 × RMS among 256 Gaussian values: how much it hurts its block neighbours in MXFP4, NVFP4, INT4 g128 and NF4 (open)

Older links such as ?v=0.1&fmt=e4m3 still work.

Runs entirely in your browser; nothing you type leaves this page.