好的,我已经阅读了关于这个主题的一些内容:
How to deal with floating point number precision in JavaScript?
Is floating point math broken?
Why can't decimal numbers be represented exactly in binary?
我的问题不是它为什么会发生,或者如何解决它。
这是关于是否有预测它将会发生的方法,然后只有在它发生时才使用解决方案。除此之外,我还想要一个低计算成本的解决方案。
我进行了一些测试,我觉得这类问题需要有条件才能发生,但我不确定:
console.log("1st calc", parseFloat(-24.05) + parseFloat(24.05));
console.log("2nd calc", parseFloat(-12.003) + parseFloat(12.003) + parseFloat(-24.05) + parseFloat(24.05));
console.log("3rd calc", parseFloat(-12.003) + parseFloat(-24.05) + parseFloat(12.003) + parseFloat(24.05));
console.log("4th calc", parseFloat(12.003) + parseFloat(24.05) + parseFloat(-12.003) + parseFloat(-24.05));
console.log("5th calc", parseFloat(12.006) + parseFloat(-12.006) + parseFloat(2.007) + parseFloat(-2.007) + parseFloat(1.009) + parseFloat(-1.009));
console.log("6th calc", parseFloat(12.006) + parseFloat(2.007) + parseFloat(1.009) + parseFloat(-12.006) + parseFloat(-2.007) + parseFloat(-1.009));
console.log("7th calc", parseFloat(12.05) + parseFloat(2.003) + parseFloat(1.005) + parseFloat(7.01) + parseFloat(-12.05) + parseFloat(-2.003) + parseFloat(-1.005) + parseFloat(-7.01));
console.log("8th calc", parseFloat(12.05) + parseFloat(-12.05) + parseFloat(2.003) + parseFloat(-2.003) + parseFloat(1.005) + parseFloat(-1.005) + parseFloat(7.01) + parseFloat(-7.01));
我知道这个数字是否具有精确的二进制表示,但要知道这是一个很长的计算,那么是否有更快/更容易的预测方法?
问题是,我想要一个脚本来测试它是否具有精确的二进制表示,然后仅在需要时应用解决方案。但我希望它比将解决方案应用于每个浮点数更快。我不知道是否可能。
像
这样的东西def power_of_2?(number)
return true if number == 1
return false if number == 0 || number % 2 != 0
power_of_2?(number / 2)
end
可能有助于知道数字是否具有精确的二进制表示,但我甚至不确定它对于诸如1.300005407之类的数字是否足够准确。
例如,使用我在上面的测试中编写的数字,我觉得在parseFloat()(这里解决问题)中将它们全部乘以1000比将它们逐个测试更快。
我在测试中注意到的一点是,根据您添加数字的方式,问题是否发生:
console.log("7th calc", parseFloat(12.05) + parseFloat(2.003) + parseFloat(1.005) + parseFloat(7.01) + parseFloat(-12.05) + parseFloat(-2.003) + parseFloat(-1.005) + parseFloat(-7.01));
console.log("8th calc", parseFloat(12.05) + parseFloat(-12.05) + parseFloat(2.003) + parseFloat(-2.003) + parseFloat(1.005) + parseFloat(-1.005) + parseFloat(7.01) + parseFloat(-7.01));
使用相同的数字,但顺序不同,结果完全不同。
有什么想法吗?
答案 0 :(得分:2)
嗯,愚蠢容易但不完美的方法是以比你需要的更高的精度进行解析,并检查转换到你想要的精度并不会改变它的值。这不是很正确,因为稀有值不能表示为double,但最接近的double表示将是精确浮点数(例如1.00000000000000001)。
完美但不一定实用的方法是解析两次,每次使用不同的浮点舍入模式:首先是圆形到正无穷大,然后是圆形到负无穷大。如果两个结果相同,则输入可以完全表示。问题是,并非所有字符串到浮点的实现都表现出正确的WRT舍入模式,因此您需要测试这是否适合您。 (当然,这只适用于控制舍入模式的环境。)这种方法也适用于除字符串到浮点数之外的操作,但是对于某些操作(如减法)有更好的适应方法。
您也可以考虑将浮点值转换回字符串并进行字符串比较。但是,这很麻烦,因为您不得不担心您的输入是否是规范形式。