你可以找到很多关于浮点精度错误以及如何在Javascript中避免使用它们,例如"How to deal with floating point number precision in JavaScript?",他们通过将数字四舍五入到固定的小数位来处理问题。
我的问题略微不同,我从后端获取数字(有些带有舍入错误)并希望显示而不错误。
当然,我可以使用value.toFixed(X)
将数字四舍五入到设定的小数位数。问题是,数字的范围可以从0.000000001到1000000000,所以我永远无法确定有效的小数位数。
(请参阅此Fiddle以了解我的无用尝试) 代码:
var a = 0.3;
var b = 0.1;
var c = a - b; // is 0.19999999999999998, is supposed to be 0.2
// c.toFixed(2) = 0.20
// c.toFixed(4) = 0.2000
// c.toFixed(5) = 0.200000
var d = 0.000003;
var e = 0.000002;
var f = d - e; // is 0.0000010000000000000002 is supposed to be 0.000001
// f.toFixed(2) = 0.00
// f.toFixed(4) = 0.0000
// f.toFixed(5) = 0.000001
var g = 0.0003;
var h = 0.0005;
var i = g + h; // is 0.0007999999999999999, is supposed to be 0.0008
// i.toFixed(2) = 0.00
// i.toFixed(4) = 0.0008
// i.toFixed(5) = 0.000800
我的问题现在是,如果有任何算法,智能地检测合理的小数位数并相应地舍入数字?
答案 0 :(得分:1)
当十进制数字四舍五入为二进制浮点数时,无法从结果中知道原始数字是多少或有多少有效数字。无限多的十进制数字将四舍五入到相同的结果。
然而,舍入误差是有界的。如果已知原始号码具有至多一定数量的数字,则仅具有该数字位数的十进制数字是候选者。如果这些候选者中只有一个与二进制值的差异小于最大舍入误差,则该值必须是原始数字。
如果我没记错(我不经常使用JavaScript),JavaScript使用IEEE-754 64位二进制文件。对于这种格式,已知任何15位十进制数字都可以转换为这种二进制浮点格式并且没有错误地返回。因此,如果原始输入是十进制数字,最多有15位有效数字,并且它被转换为64位二进制浮点数(并且没有对其执行其他可能引入其他错误的操作),并且您格式化二进制浮点值作为15位十进制数字,您将拥有原始数字。
结果十进制数字可能有尾随零。不可能(仅从二进制浮点值)知道这些是否在原始数字中。
答案 1 :(得分:0)
由于Eric的回答,一个班轮解决方案:
const fixFloatingPoint = val => Number.parseFloat(val.toFixed(15))
fixFloatingPoint(0.3 - 0.1) // 0.2
fixFloatingPoint(0.000003 - 0.000002) // 0.000001
fixFloatingPoint(0.0003 + 0.0005) // 0.0008