为什么我需要17位有效数字(而不是16位)才能代表双倍数?

时间:2011-05-25 00:11:13

标签: c floating-accuracy

有人能给我一个浮点数(双精度)的例子,需要超过16个有效十进制数来表示它吗?

我在this thread找到了有时你需要多达17位的数字,但是我找不到这样一个数字的例子(16对我来说似乎足够了)。

有人可以澄清这个吗?

非常感谢!

5 个答案:

答案 0 :(得分:10)

我的另一个答案是错误的。

#include <stdio.h>

int
main(int argc, char *argv[])
{
    unsigned long long n = 1ULL << 53;
    unsigned long long a = 2*(n-1);
    unsigned long long b = 2*(n-2);
    printf("%llu\n%llu\n%d\n", a, b, (double)a == (double)b);
    return 0;
}

编译并运行以查看:

18014398509481982
18014398509481980
0

a和b只是2 *(2 ^ 53-1)和2 *(2 ^ 53-2)。

这些是17位数的基数为10的数字。四舍五入到16位时,它们是相同的。然而a和b显然只需要53位精度来表示base-2。因此,如果你拿a和b并将它们加倍,你得到反例。

答案 1 :(得分:1)

我认为该线程上的人是错误的,16个基数为10的数字总是足以代表IEEE的两倍。

我对证据的尝试会是这样的:

另外假设。然后,必须有两个不同的双精度数字必须用相同的16位有效数字的基数10来表示。

但是两个不同的双精度数必须相差2 ^ 53中的至少一个部分,这大于10 ^ 16中的一个部分。并且在10 ^ 16中,没有两个数字相差超过一个部分可能会舍入到相同的16位有效数字的基数为10的数字。

这不完全严谨,可能是错的。 : - )

答案 2 :(得分:1)

正确答案是Nemo上面的答案。在这里,我只是粘贴一个简单的Fortran程序,显示两个数字的示例,需要17位数的精度进行打印,显示,如果不需要,则需要(es23.16)格式来打印双精度数字松开任何精度:

program test
implicit none
integer, parameter :: dp = kind(0.d0)
real(dp) :: a, b
a = 1.8014398509481982e+16_dp
b = 1.8014398509481980e+16_dp
print *, "First we show, that we have two different 'a' and 'b':"
print *, "a == b:", a == b, "a-b:", a-b
print *, "using (es22.15)"
print "(es22.15)", a
print "(es22.15)", b
print *, "using (es23.16)"
print "(es23.16)", a
print "(es23.16)", b
end program

打印:

First we show, that we have two different 'a' and 'b':
a == b: F a-b:   2.0000000000000000     
using (es22.15)
1.801439850948198E+16
1.801439850948198E+16
using (es23.16)
1.8014398509481982E+16
1.8014398509481980E+16

答案 3 :(得分:0)

深入研究单精度和双精度基础知识,并断言这个或那个(16-17)很多DECIMAL数字的概念并开始考虑(53)BINARY数字。如果你花一些时间挖掘,可以在stackoverflow找到必要的例子。

我没有看到如何在没有合格的BINARY解释的情况下给予DECIMAL答案的人给出最佳答案。这个东西很简单,但并不简单。

答案 4 :(得分:0)

可以用双精度(8字节IEEE)精确表示的最大连续整数范围是-2 ^ 53到2 ^ 53(-9007199254740992。到9007199254740992)。数字-2 ^ 53-1和2 ^ 53 + 1不能用双精确表示。

因此,小数点左边不超过16位有效十进制数字将精确表示连续范围内的双精度数。