转换为科学计数法时出现双精度误差

时间:2015-03-04 04:43:41

标签: c++ unix precision double-precision scientific-notation

我正在构建一个程序,将双值转换为科学值格式(尾数,指数)。然后我注意到了下面的

369.7900000000000 -> 3.6978999999999997428

68600000 -> 6.8599999999999994316

我也注意到了其他几个值的相同模式。最大分数误差为

0.000 000 000 000 001 = 1*e-15

我知道在计算机中表示double值的不准确性。可以得出结论,我们得到的最大分数误差是1*e-15吗?这有什么重要意义?

我经历了关于堆栈溢出中浮点精度问题的大部分问题,但我没有看到任何关于64位的最大小数误差。

为了清楚我的计算,我也提到了我的代码片段

double norm = 68600000;
if (norm)
{
    while (norm >= 10.0)
    {
      norm /= 10.0;
      exp++;
    }
    while (norm < 1.0)
    {
      norm *= 10.0;
      exp--;
    }
}

现在我

norm = 6.8599999999999994316;
exp = 7

1 个答案:

答案 0 :(得分:2)

您获得的号码与double数据类型的machine epsilon相关。

A double是64位长,符号为1位,指数为11位,尾数小数为52位。 <{1}}的值由

给出
double

尾数只有52位,1.mmmmm... * (2^exp) 以下的任何double值都会因为其重要性较小而添加到2^-52时完全丢失。在二进制文件中,1.0将是

1.0 + 2^-52

显然,任何较低的值都不会改变1.000...00 + 0.000...01 = 1.000.....01 的值。您可以自己验证程序中的1.0

此数字1.0 + 2^-53 == 1.0称为机器epsilon ,并且是由于与2^-52 = 2.22e-16的舍入错误导致的一个浮点运算期间发生的相对错误的上限值。

类似地,double在其尾数中有23位,因此其机器epsilon为float

你得到2^-23 = 1.19e-7的原因可能是因为你在执行许多算术运算时累积了错误,但我不能说因为我不知道你正在做的确切计算。


编辑:我已经查看了68600000问题的相对错误。

首先,您可能有兴趣知道round-off错误可能会改变您的计算结果,如果您将其分解为步骤:

1e-15

在第一行中,最接近的686.0/10.0 = 68.59999999999999431566 686.0/10.0/10.0 = 6.85999999999999943157 686.0/100.0 = 6.86000000000000031974 到68.6低于实际值,但在第三行中,我们看到最接近的double到6.86更大。

如果我们查看您的计划的绝对错误 double,我们会发现它是

e_abs = abs(v-v_approx)

然而,相对错误 6.8600000 - 6.85999999999999943156581139192 ~= 5.684e-16 将是

e_abs = abs( (v-v_approx)/ v) = abs(e_abs/v)

这确实低于5.684e-16 / 6.86 ~= 8.286e-17 的机器epsilon。

This是一篇着名的论文,如果你想了解浮点运算的所有细节,你可以阅读。