在讨论here和here中,我们看到toFixed()
可用于帮助维护使用二进制浮点数时的精度。
由于各种原因,我不想使用第三方库。但是,对于任何可以在64位内表示为有限小数的分数,我希望以最通用的方式保持最大精度。
假设我使用toFixed()
,我什么时候需要使用它?并且有一个最好的"为了实现上述目标,我可以传递给它的论点?
例如,考虑JavaScript能够在不同操作后将1/10分数表示为有限小数:
10/100 = 0.1
0.09 + 0.01 = 0.09999999999999999
1.1 - 1 = 0.10000000000000009
第一步不需要修正步骤,而最后两步则不需要。此外,传递toFixed()
值为15适用于此情况(例如:Number((0.09 + 0.01).toFixed(15))
):
10/100 = 0.1
0.09 + 0.01 = 0.1
1.1 - 1 = 0.1
但是传递16不会:
10/100 = 0.1
0.09 + 0.01 = 0.1
1.1 - 1 = 0.1000000000000001
尝试JSFIDDLE。
作为toFixed()
的论据15会不会达到上述目标?更重要的是,我什么时候打电话给toFixed()
?除了加,减,乘和除之外,我的数学例程还使用Math.pow()
,Math.exp()
和Math.log()
。
答案 0 :(得分:0)
当可能发生不准确时重新开始:
除非深入了解IEEE-754双精度浮点的技术细节,并让您的代码根据其运行的两个值的特定特征进行定制,否则您将无法知道结果将是不准确的;任何操作,包括简单的添加,都可能导致不准确的结果(如着名的0.1 + 0.2 = 0.30000000000000004
示例中所示)。
重新传入toFixed
的数字:
您可以使用toFixed
(然后转换回数字)进行四舍五入(就像您在问题中一样),但您应该使用的位数由结果中所需的精度决定,以及您正在使用的价值范围。从根本上说,您需要确定所需的精度,然后使用舍入来获得最高精度的精度,因为在整个值范围内使用IEEE-754浮点无法获得完美的精度(如你懂)。你总得到15位有效数字;你需要决定如何在小数的左边和右边分配它们。
但是说你的正常"值范围小于100亿,例如,小数点后四位或五位,您可以使用5
,因为左边大约有10位数,右边大约有5位数。
以着名的例子为例:
function roundToRange(num) {
return +num.toFixed(5);
}
snippet.log(roundToRange(0.1 + 0.2)); // 0.3, rather than the usual 0.30000000000000004

<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
&#13;
圆润的结果当然可能并不完美,因为在基数2(IEEE-754使用的)中,基本10个基数为10的整数基数都是不完美的,因此必须近似值,但是通过在您的范围内工作,您可以保持范围之外的不精确度不会增加(或乘以!)。