代码之家  ›  专栏  ›  技术社区  ›  Rob

浮点误差的实际例子

  •  5
  • Rob  · 技术社区  · 14 年前

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

    6 回复  |  直到 11 年前
        1
  •  3
  •   Pascal Cuoq    11 年前

    这些 examples 来自嵌入式世界(阿里安5,爱国者),但不是浮点舍入误差严格的传感器。Ariane5是一个转换中的错误。爱国者bug是在软件的改编过程中引入的。它涉及使用一个固有的不可表示常量(恰好是看起来无害的0.10)在不同精度下进行计算。

    我预测货币价值的二元浮动有两个问题:

    • 与0.10一样常见的十进制值不能精确表示。

    • 如果精度太小,那么引发异常的干净溢出将很难跟踪精度损失。

    请注意,基本的10个浮点格式已经被精确地标准化为货币值:有些货币价值1/1000000美元,从未以少于数千美元的货币进行交换,并且您可能希望能够表示的最大金额是成比例的大,因此可伸缩表示是有意义的。其用意是尾数足够大,足以支付官方决议规定的最大金额。

        2
  •  1
  •   old_timer    14 年前

    我在一个团队中工作,该团队创建了一个FPU(硬件设计),它通过了单精度、双精度和扩展精度的TestFloat级别3。有很多坏的FPU,如果它们能捕捉到指令或异常的话,大多数都是在软件中打补丁的。我想TestFloat的家伙说主要的FPU错误是在int-to-float和float-to-int转换中,我记得Pentium4是因为这个原因失败的。不过,我通过的PentiumIII测试浮筒。我有一段时间没试过了,不知道这些多核处理器的状态是什么。不要被愚弄,以为奔腾i是唯一一个有错误的,几乎所有的,当然是大公司,都有FPU错误。IEEE754是一个糟糕的标准,让一个FPU满足这个标准是非常困难和非常昂贵的,在经历之后,我尽量避免浮点数学。编译器和C库(atof、ftoa、strtod、printf等)是问题的一部分,而不仅仅是硬件。

    单精度浮点数只有23位尾数,你将开始经常扔掉硬币或美元或数千美元。有无圆角。如果数据是随机的,四舍五入应该取平均值,这里一分钱,那里一分钱。如果被跟踪的项目总是在某个固定的大小或数量有限的单位。比如说9.99或者2个15.99的小部件,那么随机性就消失了,舍入以及尾数都会让公司或者客户的准确性付出代价。

    当然,可能有很多介于0.00和0.99之间的数字是你无法表示的,如果你处理的是小数量,你将很快进入四舍五入,而不是更晚。

    用彩车换钱是个坏主意,也许你是在找弹药来改变这一点?

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

        3
  •  0
  •   justin    14 年前

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

    个人奖金=工资*个人奖金\百分比

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

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

    总奖金=个人奖金+部门奖金+公司奖金

    其中,个人奖金百分比是基于奖金罐大小、个人评级和具有该评级的人员计算得出的值。

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

        4
  •  0
  •   Ron    14 年前

    我想你找不到真正被烧伤的人。我听说过一些公司的工资或利息计划使用的是浮点而不是固定小数,程序员从所有账户中收集小数点,以便在账户持有人不发出警报的情况下挪用资金。但是,这类事情多年前通常被悄悄地解决了。现在有了防止这种情况发生的最佳实践规则。

    另一种方法是,如果你试图从一个小样本中进行外推,那么误差会变得很大,足以让你感到困惑。就像在一个小镇上进行民意测验,试图预测全国的流行结果。

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

        5
  •  0
  •   ajs410    14 年前

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

    一个快速的Google搜索会出现这个页面,它非常详细地介绍了与模糊等号函数相关的警告。 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
  •  0
  •   Max    11 年前
    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
    

    我记得在西摩·克雷设计的超级计算机中曾经存在着错误——或者说偏心。他的乘数只检查前12位是否为零,而加法器搜索13,留下一小部分可能是0对1的数字,但另一个数字是有效的。

    威廉·卡汉的一个学生在使用IBM的360进行直升机旋翼的空气湍流模拟时,首次推出了不寻常的32位FP格式。 a - b 这两个数字的计算结果并不精确,即使两个数字在一个系数的范围内,也会导致每一个计算结果的精确度不断提高。因此,计算机给出了错误的结果。

    卡汉让他的学生用双打改写了他的代码,产生了正确的暂停点。