请考虑以下代码:

0.1 + 0.2 == 0.3  ->  false

0.1 + 0.2         ->  0.30000000000000004

为什么会发生这些不准确的情况?

最佳答案

二进制floating point数学是这样的。在大多数编程语言中,它基于IEEE 754 standard。JavaScript使用64位浮点表示,这与Java的double相同。问题的关键在于数字是用整数乘以二的幂来表示的;分母不是二的幂的有理数(如0.1,即1/10)不能精确地表示。
对于标准格式的
0.1十进制,或
binary64C99 hexfloat notation中。
相反,有理数0.1000000000000000055511151231257827021181583404541015625可以精确地写成
0x1.999999999999ap-4十进制,或
0.1类似于C99六角浮点数,其中1/10表示9的无终止序列。
程序中的常数0.10x1.99999999999999...p-4也将是它们的真值的近似值。与...最接近的0.2大于有理数0.3,而与double最接近的0.2小于有理数0.2double0.3的总和最终大于有理数0.3,因此与代码中的常量不一致。
浮点运算问题的一个相当全面的处理方法是What Every Computer Scientist Should Know About Floating-Point Arithmetic。有关更易于理解的解释,请参见floating-point-gui.de
旁注:所有的位置(基-N)数系统都有这个问题
普通的十进制(以10为基数)数字也有同样的问题,这就是为什么像1/3这样的数字最终会变成0.333333333。。。
你刚刚偶然发现了一个数字(3/10),这个数字很容易用十进制表示,但不适合二进制。它有两种方式(在某种程度上)也是:1/16是十进制的丑陋数字(0.0625),但在二进制中,它看起来和十进制的10000一样整洁(0.0001)**-如果我们习惯于在日常生活中使用基数-2的数字系统,你甚至会看到这个数字,本能地理解你可以通过减半的方法到达那里,一次又一次地减半。
**当然,这并不完全是浮点数在内存中的存储方式(它们使用科学记数法的一种形式)。然而,它确实说明了一点,即二进制浮点精度错误往往会出现,因为我们通常感兴趣的“真实世界”数字往往是10的幂,但这仅仅是因为我们每天都使用十进制数字系统这也是为什么我们会说“71%”,而不是“每7个5个”(71%是一个近似值,因为5/7不能用任何十进制数精确表示)。
所以不:二进制浮点数并没有被破坏,它们只是碰巧和其他所有的基N数系统一样不完美:)
边注:在编程中使用浮动
实际上,这个精度问题意味着您需要使用舍入函数将浮点数舍入到您感兴趣的任意多个小数位,然后才能显示它们。
还需要用允许一定公差的比较替换相等测试,这意味着:
请勿0.1
而不是0.2
需要为您的特定应用程序选择myToleranceValue,这与您准备允许多少“摆动空间”以及您将要比较的最大数量(由于精度问题)有很大关系。当心你选择的语言中的“double.Epsilon”样式常量(JavaScript中的Number.Epsilon)。这些值不能用作公差值。

07-24 09:45
查看更多