数字转比特转换器

把十进制数按 IEEE 754 摊成三段比特:1 位符号、8 或 11 位指数、23 或 52 位尾数,并给出十六进制表示。默认输入 0.1、位宽 64 位,得 3fb999999999999a,位串按 1 + 11 + 52 分组。0.1 的二进制是无限循环小数,被截断到 52 位,这正是 0.1 + 0.2 不等于 0.3 的根。

0.1 的双精度指数是 -4,尾数是 1001 循环,第 53 位起被截断,所以存进去的并不是精确的 0.1。

默认示例:0.1,位宽 64 位。输入框被清空时点「开始转换」会自动填回示例;常见数值位布局表默认显示 12 行,点「加载更多」展开到 20 行。

使用方法

  1. 数值默认 0.1,支持小数与负数。改完立即重算,光标停在输入框里按 Enter 同样触发,不必去点按钮。
  2. 位宽默认 64 位(双精度),可以切成 32 位(单精度)。切换后指数段从 11 位变成 8 位,偏移从 1023 变成 127,十六进制也从 16 位缩到 8 位。
  3. 结果区第一行给结论:数值、精度与十六进制。下面七行依次是符号位、指数位(含偏移还原)、尾数位、完整位串、1 + 11 + 52 三段分组,以及由位串回读的校验值。
  4. 符号位为 0 表示非负,1 表示负;指数位给的是偏移后的原值与减掉偏移后的真实指数,两个数都列出来,避免把偏移码当成补码读。
  5. 尾数位默认只存小数部分。整数部分的那个 1 是隐含的,不占存储位,所以 52 位尾数实际提供 53 位精度。
  6. 工具区下方是 20 行常见数值位布局表,默认显示 12 行,点「加载更多」展开余下 8 行,点「导出 CSV」存成带字节序标记的文件。
  7. 「复制结果」带走结果区整段;「复制对照表」复制正文里那张 12 行位布局表,制表符分隔,可直接粘进表格软件。
  8. 数值写成非数字会给出明确提示;输入 Infinity 与 -Infinity 会被当成合法的特殊值处理,并给出对应的位型。

这个数字转比特转换器能解决什么

浮点数在内存里是什么样,靠十进制打印值是看不出来的:0.1 打印出来是 0.1,可它存进去的并不是 0.1。数字转比特转换器这一页做的就是把十进制数按 IEEE 754 摊成 64 个(或 32 个)比特,让符号、指数、尾数三段各就各位,十六进制与位串都给全。

第一类是解释精度问题。为什么 0.1 + 0.2 不等于 0.3?把 0.1 转成比特就能看到:它的尾数是 1001 无限循环,存到第 52 位就被截断,末尾还进了一位。两个都不精确的数相加,结果自然对不上 0.3。这类问题靠讲道理讲不明白,看一次位串就懂了。

第二类是对协议与文件格式。网络协议、二进制文件、序列化格式里写的常常是 8 字节或 4 字节的浮点。要确认对方写进去的到底是单精度还是双精度、字节序怎么排,先把数值转成十六进制与位串,再和抓到的字节比对,比猜快得多。

第三类是教学与自查。讲 IEEE 754 时,「指数用偏移码」「尾数有隐含前导 1」「零与非规格化数各有专门位型」这三条都能在本页直接验证:输入 0 看全零位型,输入 1.0 看指数段正好是偏差值,输入 0.5 看指数比 1.0 小一位。

计算原理与变量说明

IEEE 754 把一个浮点数拆成三段:符号位 s、指数段 E、尾数段 M,真值为 (-1)s × 1.M × 2E-bias(规格化数)。指数不用补码而用偏移码:把真实指数加上一个偏差再存,好处是指数段全 0 到全 1 的大小顺序与真实指数一致,比较两个数时可以直接按整数比。

精度总位符号指数尾数偏移隐含精度
单精度 float32182312724 位
双精度 double6411152102353 位

指数是偏移码,不是补码。双精度偏差 1023,所以指数段 01111111011(十进制 1019)对应的真实指数是 1019 − 1023 = −4。1.0 的指数段是 01111111111(1023),真实指数 0;0.5 的指数段是 01111111110(1022),真实指数 −1。指数段从小到大正好对应真实指数从小到大,这是偏移码相对补码的好处。

尾数有隐含前导 1。规格化数的二进制一定是 1.xxxx 的形式,那个整数部分的 1 对所有规格化数都一样,于是标准干脆不存它,只存小数点后面的部分。所以 23 位尾数实际给 24 位精度,52 位实际给 53 位。指数段全 0 时例外:那时是非规格化数或零,隐含位按 0 算。

0.1 在二进制里是循环小数。十进制的 0.1 换成二进制是 0.0001100110011……,其中 1001 无限循环,永远写不完。双精度只能留 52 位,第 53 位按舍入规则进位,于是存进去的值比 0.1 略大一点点。这就是 0.1 + 0.2 !== 0.3 的根:两边都不精确。

特殊值各有专门位型。指数段全 1 且尾数全 0 是无穷(符号位决定正负),指数段全 1 且尾数非 0 是 NaN,指数段与尾数全 0 是零(同样有 +0 与 −0 之分)。所以「指数段全 1」不能当作一个很大的数来读。

完整示例(数值仅作演示)

默认一组:输入 0.1、位宽 64 位,十六进制为 3fb999999999999a,位串为 0011111110111001100110011001100110011001100110011001100110011010。按 1 + 11 + 52 分段是 0 | 01111111011 | 1001100110011001100110011001100110011001100110011010,指数段 1019 减 1023 得 −4。

对照一组:切到 32 位单精度,1.0 得 3f800000,位串 00111111100000000000000000000000;-2.5 得 c0200000,位串 11000000001000000000000000000000,符号位为 1;3.14 得 4048f5c3,位串 01000000010010001111010111000011。

双精度一组:1.0 得 3ff0000000000000,指数段 01111111111 正好是偏差 1023;3.14 得 40091eb851eb851f。把 3.14 从 64 位切到 32 位,回读值会从 3.14 变成 3.140000104904175,一眼就能看出单精度丢了多少。

常见数值位布局对照表

下表列出常见数值在两种位宽下的十六进制与分段位串。分段按「符号 | 指数 | 尾数」书写,单精度是 1 + 8 + 23,双精度是 1 + 11 + 52。「复制对照表」按钮复制的就是这张表。

数值位宽十六进制分段位串(符号 | 指数 | 尾数)
032000000000 | 00000000 | 00000000000000000000000
0.5323f0000000 | 01111110 | 00000000000000000000000
1323f8000000 | 01111111 | 00000000000000000000000
232400000000 | 10000000 | 00000000000000000000000
3.14324048f5c30 | 10000000 | 10010001111010111000011
-2.532c02000001 | 10000000 | 01000000000000000000000
-132bf8000001 | 01111111 | 00000000000000000000000
0.25323e8000000 | 01111101 | 00000000000000000000000
1003242c800000 | 10000101 | 10010000000000000000000
0.001323a83126f0 | 01110101 | 00000110001001001101111
1643ff00000000000000 | 01111111111 | 0000000000000000000000000000000000000000000000000000
0.1643fb999999999999a0 | 01111111011 | 1001100110011001100110011001100110011001100110011010

整数也有自己的位表达,只是没有指数与尾数之分:255 的二进制是 11111111(8 位),1024 是 10000000000(11 位),65535 是 1111111111111111(16 位),65536 是 10000000000000000(17 位)。整数每多一位就多一倍的取值范围,浮点则把位分给了指数与尾数,这是两者最根本的区别。

十进制整数最少位宽二进制
010
111
255811111111
10241110000000000
65535161111111111111111
655361710000000000000000

把这两张表对着看,能看清浮点到底省掉了什么:整数 65535 用 16 位就能精确表示,而双精度用了 64 位,换来的不是「把 65535 存得更准」,而是能同时表示 0.0000001 与 10000000000 这种跨度极大的数。代价是精度按有效位分配:数值越大,相邻两个可表示的数之间隔得越远,超过 2 的 53 次方的整数就已经无法逐个区分了。所以金额、计数这类要求分毫不差的场景不该用浮点,而科学计算、图形与信号处理恰恰需要这种「范围换精度」的设计。

结果边界、舍入与适用说明

常见问题

为什么 0.1 存进去不是精确的 0.1?

0.1 换成二进制是 0.0001100110011……,1001 无限循环。双精度只留 52 位尾数,第 53 位按舍入进位,于是存的是比 0.1 略大一点的值。

0.1 + 0.2 为什么不等于 0.3?

因为 0.1 与 0.2 都是被截断过的近似值,相加后误差累积,得到的是 0.30000000000000004,而 0.3 又是另一个近似值,两者不相等。

指数为什么不用补码?

偏移码让指数段的大小顺序与真实指数一致,两个浮点数可以直接按整数比较大小;补码做不到这一点。双精度偏差是 1023,单精度是 127。

尾数为什么少一位?

规格化数的整数部分恒为 1,标准把这个 1 省掉不存,只存小数部分。所以 52 位尾数实际提供 53 位精度,23 位实际提供 24 位。

32 位和 64 位差多少?

指数从 8 位变 11 位,尾数从 23 位变 52 位。有效精度从约 7 位十进制涨到约 16 位,取值范围也大幅扩大。

回读值和输入不一样,是算错了吗?

不是。切到 32 位时,数值先被舍入到单精度再回读,3.14 会读成 3.140000104904175,这正是单精度的精度上限。

位串的顺序和内存里的字节一样吗?

不一定。本页按大端位序书写(符号、指数、尾数),内存字节还受处理器的字节序影响,小端机器上字节顺序是反的。

输入的数据会上传到服务器吗?

不会。转换、查表与导出都在本页完成,没有发起任何网络请求,也不写入浏览器存储,刷新页面即恢复默认值。

相关工具