考虑以下代码:
0.1 + 0.2 == 0.3 -> false
0.1 + 0.2 -> 0.30000000000000004
为什么会出现这些错误?
考虑以下代码:
0.1 + 0.2 == 0.3 -> false
0.1 + 0.2 -> 0.30000000000000004
为什么会出现这些错误?
当前回答
除了其他正确答案之外,您可能还需要考虑缩放值以避免浮点运算的问题。
例如:
var result = 1.0 + 2.0; // result === 3.0 returns true
…而不是:
var result = 0.1 + 0.2; // result === 0.3 returns false
在JavaScript中,表达式0.1+0.2===0.3返回false,但幸运的是,浮点中的整数运算是精确的,因此可以通过缩放来避免十进制表示错误。
作为一个实际的例子,为了避免精度至关重要的浮点问题,建议1将钱作为一个整数来处理:2550美分而不是25.50美元。
1 Douglas Crockford:JavaScript:好的部分:附录A——糟糕的部分(第105页)。
其他回答
这个问题的许多重复问题都是关于浮点舍入对特定数字的影响。在实践中,通过查看感兴趣的计算的确切结果而不是仅仅阅读它,更容易了解它的工作原理。一些语言提供了实现这一点的方法,例如在Java中将浮点或双精度转换为BigDecimal。
由于这是一个语言不可知的问题,因此需要语言不可知工具,例如十进制到浮点转换器。
将其应用于问题中的数字,视为双精度:
0.1转换为0.1000000000000000055511151231257827021181583404541015625,
0.2转换为0.200000000000000011102230246251565404236316680908203125,
0.3转换为0.299999999999999988897769753748434595763683319091796875,以及
0.300000000000000004转换为0.30000000000000000444089209850062616169452667236328125。
手动或在十进制计算器(如Full Precision calculator)中添加前两个数字,显示实际输入的精确和为0.30000000000000000166533453693773481063544750213623046875。
如果四舍五入到等于0.3,则舍入误差将为0.000000000000000027755575615628913510591702705078125。四舍五入等于0.300000000000000004也会产生舍入误差0.000000000000000027755575615628913510591702705078125。打成平手的规则适用。
返回浮点转换器,0.300000000000000004的原始十六进制是3fd333333333334,以偶数结尾,因此是正确的结果。
它被打破的方式与你在小学学习并每天使用的十进制(以10为基础)表示法完全相同,只是以2为基础。
要理解,请考虑将1/3表示为十进制值。这是不可能做到的!世界将在你写完小数点后的3之前结束,所以我们写了一些地方,认为它足够准确。
以同样的方式,1/10(十进制0.1)不能以2为基数(二进制)精确地表示为“十进制”值;小数点后的重复模式将永远持续下去。该值不精确,因此无法使用常规浮点方法对其进行精确计算。与基数10一样,还有其他值也显示了这个问题。
我刚刚看到了关于浮点数的有趣问题:
考虑以下结果:
error = (2**53+1) - int(float(2**53+1))
>>> (2**53+1) - int(float(2**53+1))
1
当2**53+1时,我们可以清楚地看到一个断点——直到2**53,所有的工作都正常。
>>> (2**53) - int(float(2**53))
0
发生这种情况的原因是双精度二进制:IEEE 754双精度二进制浮点格式:binary64
从维基百科的双精度浮点格式页面:
双精度二进制浮点是PC上常用的格式,因为它的范围比单精度浮点更广,尽管它的性能和带宽成本很高。与单精度浮点格式一样,与相同大小的整数格式相比,它缺少整数的精度。它通常简称为double。IEEE 754标准规定二进制64具有:符号位:1位指数:11位有效精度:53位(显式存储52位)具有给定偏置指数和52位分数的给定64位双精度数据假设的实际值为或
感谢@aguest向我指出了这一点。
浮点舍入错误。由于缺少5的素因子,0.1在基-2中不能像在基-10中那样精确地表示。正如1/3以十进制表示需要无限位数,但以3为基数表示为“0.1”,0.1以2为基数表示,而以10为基数不表示。计算机没有无限的内存。
我可以补充一下吗;人们总是认为这是一个计算机问题,但如果你用手(以10为基数)计算,你就不能得到(1/3+1/3=2/3)=真,除非你有无穷大可以将0.333…加到0.333……就像(1/10+2/10)一样==基数2的3/10问题,您将其截断为0.333+0.333=0.666,并可能将其舍入为0.667,这在技术上也是不准确的。
用三进制数,三分之三不是问题——也许有人会问为什么你的十进制数学被打破了。。。