【问题标题】:Javascript for loop doing bad math [duplicate]Javascript for循环做不好的数学[重复]
【发布时间】:2014-03-20 09:43:33
【问题描述】:
有谁知道编程语言的核心、基本功能如何失去正确/精确计算的能力?
http://jsfiddle.net/krazyjakee/v3XCQ/
var html = '';
for(var i = 0; i <= 1; i += 0.01){
html += i + '<br />';
}
document.body.innerHTML = html;
我的问题只是为什么会发生这种情况,我该如何阻止它发生?
0
0.01
0.02
0.03
0.04
0.05
0.060000000000000005
0.07
0.08
0.09
0.09999999999999999
0.10999999999999999
【问题讨论】:
标签:
javascript
loops
for-loop
【解决方案1】:
为什么我的数字,比如 0.1 + 0.2 加起来不是很好的 0.3 轮,而是得到一个奇怪的结果,比如 0.30000000000000004?
因为在内部,计算机使用的格式(二进制浮点)根本无法准确表示像 0.1、0.2 或 0.3 这样的数字。
在编译或解释代码时,您的“0.1”已经四舍五入到该格式中最接近的数字,这会在计算发生之前导致一个小的舍入误差。
为什么计算机会使用如此愚蠢的系统?
这并不愚蠢,只是不同。十进制数不能准确地表示像 1/3 这样的数字,因此您必须四舍五入到 0.33 之类的值 - 而且您也不希望 0.33 + 0.33 + 0.33 加起来等于 1 - 是吗?
计算机使用二进制数字是因为它们处理这些数字的速度更快,而且对于大多数计算,小数点后 17 位的微小错误根本不重要,因为您使用的数字不是四舍五入的(或者精确)无论如何。
我可以做些什么来避免这个问题?
这取决于你在做什么样的计算。
如果您确实需要将结果精确地相加,尤其是当您使用金钱时:请使用特殊的十进制数据类型。
如果您只是不想看到所有这些额外的小数位:只需在显示结果时将结果格式化为固定的小数位数。
如果您没有可用的十进制数据类型,另一种方法是使用整数,例如完全以美分计算金钱。但这是更多的工作并且有一些缺点。
为什么 0.1 + 0.4 等其他计算可以正常工作?
在这种情况下,结果 (0.5) 可以精确地表示为浮点数,并且输入数字中的舍入误差可能会相互抵消 - 但这不一定是可靠的(例如当这两个数字首先以不同大小的浮点表示形式存储时,舍入误差可能不会相互抵消。
在其他情况下,例如 0.1 + 0.3,结果实际上并不是真正的 0.4,但足够接近,以至于 0.4 是比任何其他浮点数更接近结果的最短数字。然后,许多语言会显示该数字,而不是将实际结果转换回最接近的小数。
【解决方案2】:
根据定义,浮点数学并不精确。由于数字的表示精度有限,因此无法表示所有数字。
在循环中使用整数值并从中计算值。尽管这仍然是浮点值,但将数字加 1 不存在精度问题:
var html = '';
for(var i = 0; i <= 100; i++){
html += (i / 100) + '<br />';
}
document.body.innerHTML = html;
【解决方案3】:
var html = '';
for(var i = 0; i <= 1; i += 0.01){
html += i.toFixed(2) + '<br />';
}
document.body.innerHTML = html;