资讯详情

资讯详情

0.1 转二进制为什么除不尽?进制转换 21 组边界 + JS 精度实测

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/20.25 是 1/40.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?sourcedmzntgwsfsourceaddmzntgwwbwz登录后直接在对话窗口输入需求不用装软件。码道有三种使用方式WebUI浏览器对话、TUI终端命令行和桌面 IDEIDE 插件。本文用 WebUI 版演示。四、需求原文把用例先写死需求我写成 7 条重点是把要验的数写进要求里。一个输入框加一个进制选择2/8/10/16 四选一实时给出四种进制结果二进制按 4 位一组加空格。支持小数0.1 这种除不尽的小数显示 32 位二进制并标「已截断」。支持负数额外给出 32 位和 64 位补码。支持大整数用 BigInt超过 2 的 53 次方的整数不能丢精度。非法输入给中文提示并保留上一次的有效结果。页面顶部一个「运行自检」按钮跑 20 组固定用例并显示通过数。深色界面中文标签全部本地计算。最后单独加一句完成后打开预览让我直接看到运行效果。五、页面上有哪几块页面就四块从上到下。顶部是工具栏一个「运行自检」按钮加一行统计。下面一行是输入区左边填数值右边选输入进制。中间是四张结果卡二进制、八进制、十进制、十六进制各一张。最下面是补码卡只在输入负数时出现给出 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要查某个数的二进制或者补码把输入框当计算器用就行。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →