Dev tool

浮点数转换

十进制与 FP16 / BF16 / FP32 互转。给出位模式、符号指数尾数分解, 并标出这个数属于规格数、非规格数还是特殊值。

十进制数值

支持科学计数法(如 6.1e-5)与特殊值(Infinity / NaN)。 也可以直接改下面任一格式的十六进制位模式反向换算。

FP16

1 + 5 + 10 bias 15
—
· ··· ···
十六进制
十进制 —
符号 / 指数 / 尾数 —
可表示范围 最大 65504 规格 ≥ 6.104e-5 非规格 ≥ 5.960e-8
零 非规格 规格数 Inf / NaN

—

BF16

1 + 8 + 7 bias 127
—
· ··· ···
十六进制
十进制 —
符号 / 指数 / 尾数 —
可表示范围 最大 3.390e38 规格 ≥ 1.175e-38 非规格 ≥ 9.184e-41
零 非规格 规格数 Inf / NaN

—

FP32

1 + 8 + 23 bias 127
—
· ··· ···
十六进制
十进制 —
符号 / 指数 / 尾数 —
可表示范围 最大 3.403e38 规格 ≥ 1.175e-38 非规格 ≥ 1.401e-45
零 非规格 规格数 Inf / NaN

—

特殊值位模式

每个格式里这些值的位模式是固定的,可以直接对照硬件波形或寄存器 dump。

FP16

+0
0x0000
-0
0x8000
+Inf
0x7C00
-Inf
0xFC00
qNaN
0x7E00
sNaN
0x7C01
最大有限值
0x7BFF
最小规格数
0x0400
最小非规格数
0x0001

BF16

+0
0x0000
-0
0x8000
+Inf
0x7F80
-Inf
0xFF80
qNaN
0x7FC0
sNaN
0x7F81
最大有限值
0x7F7F
最小规格数
0x0080
最小非规格数
0x0001

FP32

+0
0x00000000
-0
0x80000000
+Inf
0x7F800000
-Inf
0xFF800000
qNaN
0x7FC00000
sNaN
0x7F800001
最大有限值
0x7F7FFFFF
最小规格数
0x00800000
最小非规格数
0x00000001

三种格式怎么选

位宽决定了它能表示多大的范围和多少有效数字。三者的结构对比:

  • FP16:1 位符号 + 5 位指数 + 10 位尾数,2 字节。最大 65504,最小规格数 6.1e-5。范围小但精度够用,推理场景常用。
  • BF16:1 + 8 + 7,2 字节。指数位数和 FP32 完全一样,所以范围与 FP32 相同,但只有 8 位有效数字。训练时梯度容易溢出,用 BF16 更安全。
  • FP32:1 + 8 + 23,4 字节。最大约 3.4e38,有效数字 24 位,通用计算的标准格式。

一句话记法:BF16 是「砍掉尾数的 FP32」,FP16 是「砍掉一半指数、保留较多尾数」。 前者保范围,后者保精度。

规格数与非规格数

指数位全 0 且尾数非 0 时,这个数是非规格数(subnormal)。 此时隐含的前导 1 不再存在,数值按 0.尾数 × 2^(1-bias) 计算。

为什么要这样设计?因为如果直接跳到 0,最小的规格数和 0 之间会有一段巨大的空隙, 差值计算会出现诡异的断层。非规格数让下溢变成渐进的,这在硬件上叫渐进下溢(gradual underflow)。 代价是尾数有效位会随着数值变小而减少。

特殊值一览

所有特殊值都靠指数位全 1 来表示,再用尾数区分: 尾数全 0 是无穷,尾数非 0 是 NaN。NaN 再看尾数最高位—— 为 1 是静默 NaN(qNaN),为 0 是信号 NaN(sNaN)。 ±0 则是指数和尾数全都为 0,只靠符号位区分。

常见问题

FP16、BF16、FP32 有什么区别?

三者位宽不同:FP16 是 1+5+10 位,指数 5 位所以范围只有 ±65504,但尾数 10 位、精度还行;BF16 是 1+8+7 位,指数和 FP32 一样是 8 位,所以范围和 FP32 相同(约 ±3.4e38),但尾数只有 7 位,精度很低;FP32 是 1+8+23 位,范围和精度都够,但占 4 字节。AI 推理常用 FP16,训练常用 BF16——因为训练更怕溢出、不怕精度差。

为什么 0.1 转成 FP16 不是精确的 0.1?

0.1 在二进制里是无限循环小数(0.0001100110011…),任何二进制浮点格式都存不下。FP16 只能保存最接近的 0.0999755859375,位模式是 0x2E66。页面上会标出「已舍入」,并显示实际存下来的值。

非规格数(subnormal)是什么?

当数值小到指数已经到最小值时,格式会放弃隐含前导 1,改用「指数全 0 + 尾数直接表示」的方式,这样能继续表示更小的数,代价是有效位数逐渐减少。FP16 的最小规格数是 6.1e-5,最小非规格数是 5.96e-8——非规格数让下溢变成了渐进式的,而不是直接变成 0。

qNaN 和 sNaN 有什么区别?

q 是 quiet(静默),参与运算时继续传播、不报错;s 是 signaling(信号),参与运算会触发无效操作异常。区分方法是看尾数最高位:为 1 是 qNaN,为 0 且尾数非 0 是 sNaN。两者指数位都是全 1。

这个转换和硬件里的行为一致吗?

舍入采用 IEEE 754 默认的「就近舍入、中间值取偶」(round-half-even)。已用 5000 多个随机样本与 IEEE 原生 Float32 逐位比对,结果完全一致。溢出时返回 ±Inf,下溢到非规格数区间时按最小单位量化。

数据会不会上传?

不会。整个转换在浏览器里用 JavaScript 完成,页面没有后端接口,断网也能用。