Warm tip: This article is reproduced from serverfault.com, please click

language agnostic-浮点数学运算是否被破坏?

(language agnostic - Is floating point math broken?)

发布于 2009-02-25 21:39:02

考虑以下代码:

0.1 + 0.2 == 0.3  ->  false
0.1 + 0.2         ->  0.30000000000000004

为什么会出现这些错误?

Questioner
Cato Johnston
Viewed
11
community wiki 2020-10-20 14:51:28

二进制浮点数学就是这样。在大多数编程语言中,它基于IEEE 754标准问题的症结在于数字以这种格式表示为整数乘以2的幂。分母不是2的幂的有理数(例如0.1,是1/10)无法精确表示。

对于0.1标准binary64格式,表示形式可以完全按照

相比之下,合理数量0.1,这是1/10可以完全按照书面

  • 0.1 以十进制表示,或
  • 0x1.99999999999999...p-4以C99十六进制表示法的类似形式表示,其中...表示9的无休止序列。

常量0.20.3程序中的常量也将接近其真实值。碰巧最接近double0.2是大于有理数0.2,而最接近double0.3是有理数0.3的总和0.10.2卷起比有理数较大0.3,并因此与在代码中不同意恒定。

每位计算机科学家都应了解浮点算术,是对浮点算术问题的相当全面的处理有关更容易理解的说明,请参见floating-point-gui.de

旁注:所有位置(以N为底的)数字系统均会精确地共享此问题

普通的旧十进制数(以10为底)有相同的问题,这就是为什么像1/3这样的数字最终会变成0.333333333的原因...

你刚刚偶然发现了一个数字(3/10),该数字很容易用十进制表示,但不适合二进制。它也是双向的(在某种程度上):1/16是一个丑陋的数字,十进制(0.0625),但是在二进制中,它看起来像10,000十进制(0.0001)**一样整洁-如果我们在习惯于在日常生活中使用基数2的数字系统,你甚至会查看该数字,并本能地理解,可以将某物减半,一次又一次地减半,从而可以到达那里。

**当然,这并不完全是将浮点数存储在内存中的方式(它们使用科学计数法的形式)。但是,它确实说明了二进制浮点精度误差趋于增加的观点,因为我们通常感兴趣的“真实世界”数通常是10的幂-但这仅仅是因为我们使用了十进制数天-今天。这也是为什么我们要说71%而不是“每7个中有5个”的原因(71%是一个近似值,因为5/7不能用任何十进制数字精确表示)。

否:二进制浮点数没有被破坏,它们恰好与其他所有基数N的系统一样不完美:)

侧面说明:在编程中使用浮点数

实际上,这种精度问题意味着你需要使用舍入函数将浮点数四舍五入为你感兴趣的任意小数位,然后再显示它们。

你还需要用允许一定程度的容忍的比较替换相等性测试,这意味着:

千万不能if (x == y) { ... }

反而做if (abs(x - y) < myToleranceValue) { ... }

abs绝对值在哪里myToleranceValue需要针对你的特定应用程序进行选择-这与你准备允许多少“摆动空间”以及要比较的最大数字有很大关系(由于精度问题) )。注意你选择的语言中的“ epsilon”样式常量。这些不得用作公差值。