【问题标题】:upper bound for the floating point error for a number数字浮点误差的上限
【发布时间】:2013-05-18 21:53:24
【问题描述】:

关于这个主题有很多问题(和答案),但我太厚了,无法弄清楚。在 C 中,对于给定类型的浮点数,比如 double:

double x;
scanf("%lf", &x);

是否有一种通用的方法来计算传递给scanf 的小数字符串与x 现在的内部表示之间的误差的上限(尽可能小)?

如果我理解正确,有时会出现错误,并且会随着小数部分的绝对值的增加而增加(换句话说,0.1 会有点偏离,但 100000000.1 会偏离更多)。

【问题讨论】:

    标签: c floating-point


    【解决方案1】:

    C 标准的这一方面的规定稍显不足,但您可以预期从十进制到 double 的转换在原始 Unit in the Last Place 的一个范围内。

    您似乎正在寻找转换的绝对错误的界限。有了上述假设,您可以将double 这样的界限计算为DBL_EPSILON * xDBL_EPSILON 通常为 2^-52。

    可以按如下方式计算转换过程中可能产生的错误的更严格界限:

    double va = fabs(x);
    double error = nextafter(va, +0./0.) - va;
    

    最好的转换函数保证在默认的舍入到最近模式下转换为半个 ULP。如果您使用具有此保证的转换函数,您可以将我提供的界限除以二。


    上述情况适用于以十进制表示的原始数字为 0 或其绝对值介于 DBL_MIN(约 2*10^-308)和DBL_MAX(约 2*10^308)之间的情况。如果非空十进制数的绝对值小于DBL_MIN,则绝对误差仅以DBL_MIN * DBL_EPSILON 为界。如果绝对值高于DBL_MAX,则转换的结果很可能是无穷大。

    【讨论】:

    • 非常感谢!你能给我指个参考吗?这个值是不是有点太高了?
    • @Boris 我会寻找参考。公式 DBL_EPSILON * x 被过度近似最多为 2 倍。我将通过更优化的 ULP 计算来完成我的答案。
    • @Boris 我在答案中放置了一个链接,指向专家撰写的关于“ULP”最佳定义的小册子。维基百科上有很多信息:en.wikipedia.org/wiki/IEEE_floating_point。最后,由于您使用的是 C,因此使用格式 %a(用于打印带有尾数的十六进制表示的 double)和浮点常量的输入格式 0x1.1239abcp10 对理解表示有很长的路要走.
    • @Boris 哦,最后一件事:我曾经认为我可以假设标准库中的十进制到浮点函数在 1/2 ULP 之内。我很失望,长话短说,我不得不自己写。如果您不关心性能,这很容易:blog.frama-c.com/index.php?post/2011/11/18/…
    【解决方案2】:

    您不能以 10 为基数来考虑这一点,错误以 2 为基数,它不一定指向以 10 为基数的特定小数位。

    您的问题有两个潜在问题,首先 scanf 获取一个 ascii 字符串并将其转换为二进制数,这是一个使用多个 C 库的软件。例如,我已经看到编译时解析与运行时解析在同一系统上给出不同的转换结果。因此,就错误而言,如果您想要一个确切的数字,请自行转换并将该二进制数放入寄存器/变量中,否则接受您通过转换获得的结果并了解可能会出现您没想到的转换的舍入或剪裁(这会导致准确性问题,您没有得到预期的数字)。

    帕斯卡已经回答了第二个真正的问题。如果二进制位置,你只有 x 数。就小数而言,如果您有 3 个小数位,则数字 1.2345 必须表示为 1.234 或 1.235。如果您有 3 位尾数,则二进制相同,则 1.0011 是 1.001 或 1.010,具体取决于舍入。 IEEE 浮点数的尾数长度有据可查,你可以简单地用谷歌搜索每个精度有多少二进制位。

    【讨论】:

    • 感谢您的回答。我想固有的问题是我必须使用已经是 double 的数字,而且我不知道原始的 ascii 字符串是什么。这就是为什么我需要绝对误差的上限。然而,第二段正好解决了我的问题!
    • 接下来是人们的困惑,当一个数字在十进制中可能看起来很简单,可能只有一个或两个有效数字,不能用浮点精确表示,当你添加更多时它会变得更糟位数。例如,在基数 3 中,数字 1/3rd 很容易表示(0.1),但在十进制中,它变成了一个无限重复的数字,出于实际编程目的,您必须剪掉一些数字。再次从那里滚雪球,从以 10 为基数的数字列表中很难看出它在浮点数中的好坏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    相关资源
    最近更新 更多