SheepDev

数值、单位与位

为什么 0.1+0.2 有时不等于 0.3?

使用工具

合计应为 0.3,屏幕却显示 0.30000000000000004。保留两位小数看起来正常,不代表根本问题解决了。近似表示与舍入发生的阶段都会影响合计和比较,应先用小表达式理解原因,而不是只隐藏尾数。

高精度计算器处理输入十进制数的四则运算,浮点内部表示工具则查看 binary32 或 binary64 编码。相同输入对应的问题不同,比较是为了选适合任务的表示,而不是宣布哪一种永远正确。

先直接计算预期表达式

输入高精度计算器
0.1 + 0.2

结果为 0.3。再用半角运算符输入 0.1 + 0.2 - 0.3,得到 0。此计算器把十进制字面值作为分数处理,中间四则运算不转为普通 Number。但无限小数的显示仍需指定精度与舍入,“高精度”不代表无限位显示。

与程序比较时应使用相同输入字符串。如果先经过其他步骤舍入再复制,条件已经不同。分别记录原始输入、实际表达式和显示前舍入,有助于找到最早出现差异的位置。

把 0.1 放进有限二进制位会怎样?

在浮点工具选择十进制输入与 binary32,输入 0.1,存储值显示为 0.10000000149011612,十六进制为 3dcccccd。有限位数选择的是接近 0.1 的值,不是完全相同值,这是表示限制而非输入错误。

再输入 0.5,同一格式存储值就是 0.5,十六进制为 3f000000。不是所有小数都有这种近似;关键是有限十进制不一定对应有限二进制,也不能据此认为所有小数运算误差相同。

显示 0.1,不证明内部精确存了 0.1

改为 binary64 后,值栏显示 0.1,十六进制为 3fb999999999999a。显示变短并不证明内部精确存了十进制 0.1,工具同时提供可读值和位表示,就是为了区分这两个视角。

比较时会暴露这种差异:显示都为 0.3 的值,内部未必相等。但到处加同一个小常数也不是通用修复。若采用容差,应依据数量尺度和所需精度制定,不应只因浮点行为就改变金额或计数规则。

这里的精度是有效数字位数

精度设置表示有效数字位数。精度 3、四舍五入时,12345 变为 12300,0.012345 变为 0.0123,不是保留小数点后三位。用于固定小数金额显示前,应确认此区别。

精度 3 时分别测试
12345
0.012345
1 / 3
(1 / 3) * 3

1÷3 显示 0.333,但 (1÷3)×3 得到 1,因为式内中间分数保留到最终输出。若复制显示值 0.333 再乘 3,结果是 0.999。把可见中间位数作为下一次输入,就改变了计算条件。

恰好一半时,舍入规则会产生不同结果

精度 2 时,1.25 用四舍五入得到 1.3,用舍入到偶数得到 1.2。后者在恰好中间时选择保留末位为偶数的一侧。1.35 两者都为 1.4,因此单个例子一致不能证明规则相同。

负数时,“向下取整”之类说法可能含糊。精度 2 的 -1.29,趋零为 -1.2,趋负无穷为 -1.3。应区分减小绝对值与数轴向左移动。规范若只写“截断”,还须确认负数与具体期望值。

逐项舍入,还是合计后舍入?

两个 1.25 若分别按两位有效数字四舍五入,得到 1.3+1.3=2.6;先相加再舍入则为 2.5。规则相同但时机不同,结果仍不同。税额、费用或积分不一致时,也要确认按单品还是订单合计处理。

正确顺序由合同或计算规范决定,不由计算器决定。舍入值无法恢复被丢弃尾数,实验应保留原输入。减少中间舍入也不总是正确;规则若要求逐项处理,省略后就是另一种计算。

可复现报告要保留表达式与舍入条件

应记录输入字符串、表达式、数值格式、有效位数、舍入规则和阶段。“1.25 在精度 2、舍入到偶数时为 1.2”可复现,“小数不对”则不行。缩短显示位数不会改变中间类型或传输精度。

依次测试简单加法、无限小数除法、恰好中间值、负数以及合计前后舍入,可把表示问题与业务规则分开。计算器检查表达式,不判断测量数据是否准确或是否符合税费制度。

精确计算不能提高原始测量的准确度

传感器只显示到十分位时,精确计算可以忠实相加输入文字,却不能恢复传感器已舍掉的部分。输出更多位不等于更了解测量对象,十位答案不会创造十位测量精度。工具不自动传播测量不确定度,因此输入来源仍需单独确认。

合同明确规定的 0.10 与传感器近似读数不同。外观相同的小数可能是精确约定、测量或其他画面已舍入的结果。仅避免浮点数不能解决这些语义,应结合输入来源,分别规定存储、中间运算和最终显示的精度规则。

参考资料

使用工具

指南 →