☰
0.1 转二进制为什么除不尽?进制转换 21 组边界 + JS 精度实测
2026/11/3 17:09:24 网站建设 项目流程

0.1 转成二进制,写出来是 0.00011001100110011001100110011001,后面还有没写完的 0011 一直在循环。

我用一个单文件网页工具跑了 21 组边界用例,页面自己报「自检结果:21 / 21 通过」。

我又用 Python 另写了一份实现,把 40 组输入逐位对着页面比,两边输出零处不一致。

比对的路上撞到三个真实的边界问题,其中一个连 2 的幂都会踩。

在线案例与源码:https://atomgit.com/deli007/demo_park/tree/main/codearts-number-base-converter

一、先说结论:几个容易写错的数

输入二进制八进制十进制十六进制容易错在哪
2551111 1111377255FF二进制按 4 位一组
0.50.10.40.50.8分母是 2 的幂,除得尽
0.10.000110011… 截断0.06314631…0.10.1999999…除不尽,要标截断
-128-1000 0000-200-128-80负数多一张补码卡
900719925474099310 0000…00014000000000000000019007199254740993200000000000012 的 53 次方加 1 不丢精度

表里的值我逐格对过页面输出,也逐格对过 Python 的结果。

二、为什么 0.1 转二进制除不尽

判据只有一条:分母是 2 的幂,二进制才写得完。

0.5 是 1/2,0.25 是 1/4,0.125 是 1/8,这三个都除得尽。

0.1 是 1/10,分母 10 里带一个因子 5。

二进制换算的每一步是乘 2 取整数位,因子 5 永远除不干净,于是 0011 无限循环。

页面按 32 位截断,标一个「已截断」,实际写下来的值是 0.099999999976716935634613037109375。

和真值差 1.4e-10,我按 3 / 21474836480 复算过一遍。

这跟 0.1 加 0.2 不等于 0.3 是同一件事:不是运算坏了,是这个数在二进制里根本没有有限表示。

三、准备环境:进入码道 Web

浏览器打开码道 Web 版:https://devcloud.cn-north-4.huaweicloud.com/chat?source=dmzntgwsf&sourcead=dmzntgwwbwz

登录后直接在对话窗口输入需求,不用装软件。

码道有三种使用方式:WebUI(浏览器对话)、TUI(终端命令行)和桌面 IDE(IDE 插件)。

本文用 WebUI 版演示。

四、需求原文:把用例先写死

需求我写成 7 条,重点是把要验的数写进要求里。

  1. 一个输入框加一个进制选择,2/8/10/16 四选一,实时给出四种进制结果,二进制按 4 位一组加空格。
  2. 支持小数,0.1 这种除不尽的小数显示 32 位二进制并标「已截断」。
  3. 支持负数,额外给出 32 位和 64 位补码。
  4. 支持大整数,用 BigInt,超过 2 的 53 次方的整数不能丢精度。
  5. 非法输入给中文提示,并保留上一次的有效结果。
  6. 页面顶部一个「运行自检」按钮,跑 20 组固定用例并显示通过数。
  7. 深色界面,中文标签,全部本地计算。

最后单独加一句:完成后打开预览,让我直接看到运行效果。

五、页面上有哪几块

页面就四块,从上到下。

顶部是工具栏,一个「运行自检」按钮加一行统计。

下面一行是输入区,左边填数值,右边选输入进制。

中间是四张结果卡,二进制、八进制、十进制、十六进制各一张。

最下面是补码卡,只在输入负数时出现,给出 32 位和 64 位两串。

自检跑起来以后,底部会多出一块用例明细,每一行一条,绿色是通过。

六、验证与踩坑

我把它落到本地打开,点了一次「运行自检」。

页面顶部写着「自检结果:21 / 21 通过」,明细里 21 行全是绿勾。

需求里写的是 20 组,它自己扩到 21 组,多出来的一条是超长输入。

光看它自己说自己对不算数,我又写了一份 Python 实现去对。

两边比了 40 组输入,覆盖整数、小数、负数、大整数、2 的幂和四种进制的混合输入,逐位对照零处不一致。

大整数那条确实靠 BigInt 撑着。

9007199254740993 是 2 的 53 次方加 1,换成普通的 Number 会变成 9007199254740992,页面给出的是原值。

接着是三个真实问题。

第一个在补码卡上。32 位补码没有范围校验,绝对值超过 2 的 31 次方就开始失真。

输入页面给的 32 位补码问题
-111111111111111111111111111111111正常
-12811111111111111111111111110000000正常
-900719925474099311111111111111111111111111111111和 -1 一模一样
-429496729600000000000000000000000000000000变成全 0

-4294967296 是 -2 的 32 次方,取模之后正好归零,页面把这个全 0 的串当成补码显示出来,没有任何提示。

第二个在截断标注上。只有二进制卡有「已截断」标,八进制、十进制、十六进制一样截断,却一声不响。

四个进制的小数位数上限分别是 32、32、60、32 位,换成实际精度是 32、96、199、128 个二进制位。

同一个 0.1,从四种进制看过去的精度并不一样。

第三个在分组上。整数部分按 4 位一组,小数部分没分,0.1 的二进制尾巴是一长串没断开的数字。

失败路径我挨个试过,报错原文有四句。

二进制里填 2,说包含二进制不合法的字符。

填 1.2.3,说小数点不能多于一个。

清空输入框,说请输入数值,输入为空。

粘贴 1001 个字符,说输入过长,超过 1000 个字符。

报错的同时结果栏不清空,我实测输入 255 之后切到二进制填 2,四张卡片还是 255 那一组值。

这算有意为之,需求里写了要保留上一次有效结果。

最后一条最小:切到 0.5 时标签看不见了,但它在页面结构里的文字还留着上一次的「已截断」,只是被隐藏。

本地复现很简单,把 index.html 存下来双击就能开。

要起个本地服务也行:

python3-mhttp.server8080

浏览器访问 http://localhost:8080/index.html 就是同一份页面。

七、使用码道的体会

把要验的数写进需求,是这次最值的一条。

21 组用例是我在需求里点名的,它照着做进了自检面板,还自己补了一条超长输入。

需求里那句「完成后打开预览」也省事,省掉了来回描述效果的时间。

不足的地方也有:补码的范围校验没做,截断标注只做了二进制这一路。

这两条我都留在文章里,没有回头去改它。

八、直接下载试玩

整页只有一个 index.html,没有任何外部依赖,拷走双击就能用。

在线案例与源码在这里:https://atomgit.com/deli007/demo_park/tree/main/codearts-number-base-converter

要查某个数的二进制或者补码,把输入框当计算器用就行。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询