math - float 学运算是否被破坏?

标签 math language-agnostic floating-point floating-accuracy

考虑以下代码:

0.1 + 0.2 == 0.3  ->  false

0.1 + 0.2         ->  0.30000000000000004

为什么会出现这些错误?

最佳答案

二进制floating point数学就是这样。在大多数编程语言中,它基于IEEE 754 standard。问题的症结在于数字以这种格式表示为整数乘以2的幂。分母不是2的幂的有理数(例如0.1,即1/10)无法准确表示。
对于标准0.1格式的binary64,表示形式可以完全按照

十进制的

  • 0.1000000000000000055511151231257827021181583404541015625
  • C99 hexfloat notation中的
  • 0x1.999999999999ap-4

  • 相反,有理数0.1(即1/10)可以完全写为

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

  • 程序中的常量0.20.3也将接近其真实值。碰巧最接近double0.2大于有理数0.2,但是最接近double0.3小于有理数0.30.10.2的总和最终大于有理数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),但是在二进制中,它看起来像十进制的10,000十分整洁(0.0001)****-如果我们在习惯在我们的日常生活中使用基数2的数字系统,您甚至会查看该数字,并且本能地理解将某物减半,一次又一次减半可以到达那里。
    **当然,这并不完全是将浮点数存储在内存中的方式(它们使用科学计数法的形式)。但是,它确实说明了二进制浮点精度误差趋于增加的观点,因为我们通常感兴趣的“真实世界”数通常是10的幂-但这仅仅是因为我们使用了十进制数天-今天。这也是为什么我们说类似71%而不是“每7个中有5个”(71%是近似值,因为5/7不能用任何十进制数字精确表示)的原因。
    否:二进制浮点数没有坏,它们恰好与其他所有base-N数系统一样不完美:)
    侧面注意:在编程中使用浮点数
    实际上,这种精度问题意味着您需要使用舍入函数将浮点数四舍五入为您感兴趣的任意小数位,然后再显示它们。
    您还需要用允许一定程度的容忍的比较替换相等性测试,这意味着:
    不做if (x == y) { ... }而是执行if (abs(x - y) < myToleranceValue) { ... }
    其中abs是绝对值。需要为您的特定应用选择myToleranceValue-这与您准备允许多少“摆动空间”以及要比较的最大数字有很大关系(由于精度下降)问题)。当心所选语言中的“epsilon”样式常量。这些不得用作公差值。

    关于math - float 学运算是否被破坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44534618/

    相关文章:

    bash - Bash 中具有浮点值的 C 风格算术

    c - 在 C 中处理小数

    java - build 雷达

    python - 圆的整数解算法?

    language-agnostic - 是否有普遍可用的 HTTPS POST 冒烟测试?

    language-agnostic - 你从哪里开始你的设计——代码、用户界面、工作流程或其他什么?

    c# - C# 是否支持任意精度算术?

    math - 使用位移位除以 10?

    algorithm - 重量平衡器算法

    零附近的 C++ 浮点比较与 Gtest 失败