我正在构建一个程序,将双值转换为科学值格式(尾数,指数)。然后我注意到了下面的
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
答案 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是一篇着名的论文,如果你想了解浮点运算的所有细节,你可以阅读。