【问题标题】:Real life example fo Floating Point error浮点错误的真实例子
【发布时间】:2010-04-28 20:21:55
【问题描述】:

是否有任何公司被浮点数据烧毁导致舍入问题的例子?我们正在实施一个新系统,所有货币价值都存储在浮点数中。我认为,如果我可以展示为什么失败的实际示例,它将比为什么无法正确存储值的理论更重要。

【问题讨论】:

    标签: floating-point


    【解决方案1】:

    这些examples 来自嵌入式世界(Ariane 5,Patriot),但严格意义上不是浮点舍入错误。 Ariane 5 错误是转换中的错误。 Patriot 错误是在软件改编过程中引入的。它涉及以不同的精度进行计算,具有一个固有的不可表示的常数(恰好是看起来无害的 0.10)。

    我预见到货币值的二进制浮点数存在两个问题:

    • 无法准确表示像 0.10 这样常见的十进制值。

    • 如果精度太小,本可以引发异常的干净溢出变成难以跟踪的精度损失。

    请注意,以 10 为基数的浮点格式已针对货币价值进行了精确标准化:某些货币价值 1/1000000 美元,兑换的金额永远不会少于数千,并且您可能希望能够达到的最大金额代表按比例大,因此可扩展的表示是有意义的。其目的是尾数足够大,以达到官方分辨率的最大总和。

    【讨论】:

    • 很好,虽然第二个说明了为什么浮动会是一件好事——如果一致的话。
    • @Michael 是的,抱歉,我想对此进行扩展,但我被叫走了。
    • 天哪...我以为我将此标记为答案。对于那个很抱歉。仅仅一年半之后……
    • 第一个示例声明“此计算是使用 24 位定点寄存器执行的”,因此这些示例都没有显示浮点舍入问题。
    • @PeteKirkham 具有讽刺意味的是,在 2010 年撰写此答案的同一个人会完全忘记它,并且独立厌倦了对 Ariane 5、Patriot 错误的肤浅分析,以至于写下这篇咆哮2012:blog.frama-c.com/index.php?post/2012/11/18/…。无论如何,我已经更新了答案,我希望现在更真实。
    【解决方案2】:

    我所在的团队创建了一个 FPU(硬件设计),该 FPU(硬件设计)通过了 testfloat 3 级的单精度、双精度和扩展精度。那里有许多糟糕的 fpus,如果它们可以捕获指令或异常,则大多在软件中修补,诸如此类。我认为 testfloat 家伙说主要的 fpu 错误是 int 到 float 和 float 到 int 的转换,我记得 pentium 4 因这个原因而失败。 pentium III I 已经通过了 testfloat。好久没试过了,不知道这些多核处理器的状态如何。不要误以为 pentium I 是唯一有错误的,几乎所有的,当然是更大的命名公司,都有 fpu 错误。 IEEE 754 是一个可怕的标准,让 fpu 满足该标准非常困难且非常昂贵,在那之后我尽可能避免使用浮点数学。编译器和 c 库(atof、ftoa、strtod、printf 等)是问题的一部分,而不仅仅是硬件。

    单精度浮点数只有 23 位尾数,您将开始经常扔掉几美分或几美元或几千美元。有或没有舍入。如果数据足够随机,则四舍五入应该是平均的,在这里获得一分钱,在那里损失一分钱。如果被跟踪的项目始终处于某个固定大小或数量有限的单位。比如说 9.99 的小部件或 15.99 的两个小部件,那么随机性就会消失,并且舍入以及尾数会在准确性方面付出代价,无论是公司还是客户。

    当然,在 0.00 到 0.99 之间可能有很多数字是您无法表示的,如果您处理的是少量数字,您迟早会进行四舍五入。

    用花车赚钱是个坏主意,也许你正在寻找弹药来改变它?

    我们有一个由软件驱动的电机控制器,使用单精度 fpu,有一段控制算法的常数必须加起来为 1.0,我不知道这个规则,我只是让一个 C 程序计算常数。我们必须手动调整其中一个常数的尾数的 lsbit,以使电机控制器稳定。

    【讨论】:

      【解决方案3】:

      我开发了一个系统来计算人们的加薪和奖金。由于部分的数量(公司绩效、部门绩效、个人绩效),计算相对复杂,但每个部分都很简单(通常是复合百分比),例如:

      personal_bonus = 薪水 *personal_bonus_percentage

      部门奖金 = 个人奖金 * 50%

      公司奖金 = 个人奖金 * 110%

      total_bonus = personal_bonus + department_bonus + company_bonus

      personal_bonus_percentage 是根据奖金池大小、个人评分和获得该评分的人计算得出的值。

      当我们测试时,我们没有手动计算(即在纸上)结果应该是什么,而是将它们与运行相同公式的 Excel 进行比较。员工确实在纸上进行了计算,当我们重写算法以解决浮点问题时,大约 5% 的奖励是错误的。

      【讨论】:

        【解决方案4】:

        我认为你不会找到真正被烧伤的人。我听说过一些公司的工资单或利息程序使用浮点数而不是固定十进制数,并且程序员从所有账户中收集小数位以盗用,而账户持有人不会发出警报。但是,这种事情通常在几年前就已经悄悄解决了。现在有最佳实践规则来防止这种事情发生。

        如果您尝试从小样本中推断,错误可能会变得大到足以让您绊倒的另一种方式。就像在一个小镇上进行民意调查,并试图预测全国的热门结果。

        前一个月我在做一个项目,我们使用矩阵数学来计算校准曲线的多项式。我们程序中的系数与电子表格中的系数完全不同。当我浏览程序和电子表格并将所有内容四舍五入到正确的有效位数时,他们非常同意。当垃圾乘以垃圾,然后平方或立方时,它就成了一个问题。

        【讨论】:

          【解决方案5】:

          我能想到的唯一真正的 FPU 错误是浮点数的相等比较。例如,0.123456 和 0.123457 非常接近;事实上,如果它们都是可能累积舍入误差的一系列计算的结果,它们很可能是相等的。不要与 == 进行比较,您应该编写一个模糊等式来确定它们是否足够接近以被视为相等。

          一个快速的谷歌搜索出现了这个页面,它详细介绍了有关模糊等于函数的相关警告。 http://adtmag.com/articles/2000/03/16/comparing-floats-how-to-determine-if-floating-quantities-are-close-enough-once-a-tolerance-has-been.aspx

          【讨论】:

            【解决方案6】:
            double: 1.000167890
            single: 1.000167847
            (b*(b-1)) - (b*b-b):  0.0000000281725079
            (a*(a-1)) - (a*a-a):  0.0000000000000001
            resultSmall - result: 0.000000028172507807931691
            double^12 - single^12:0.000000593091349143648472
            

            我记得 Seymour Cray 设计的超级计算机中曾经存在过错误或怪癖。他的乘法器只会检查前 12 位是否为零,而加法器会搜索 13 位,留下一小部分可能是零到一的数字,但另一个数字是有效的。

            William Kahan 的一个学生正在使用 IBM 的 360 对直升机旋翼进行空气湍流模拟,当时 IBM 360 首次推出了其不寻常的 32 位 fp 格式。 a - b 没有精确计算,即使这两个数字彼此相差 2 倍以内,也会导致每次计算失去准确性的问题不断升级。因此,计算机给出了错误的结果。

            Kahan 让他的学生使用双打重写他的代码,从而产生了正确的停顿点。

            【讨论】:

              猜你喜欢
              • 2020-11-21
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-03-03
              • 2011-06-05
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多