Doubles in IEE-754 have a precision of 52 bits which means they can store numbers accurately up to (at least) 251
.
If your longs are 32-bit, they will only have the (positive) range 0 .. 231 - 1
so there is no 32-bit long that cannot be represented exactly as a double. For a 64-bit long, it will be (roughly) 252
so I'd be starting around there, not at zero.
您可以使用以下程序来检测故障开始发生的位置。在早期版本中,我依赖于这样一个事实:连续加倍的数字的最后一位数字遵循序列 {2,4,8,6}。然而,我最终选择使用已知的可信工具(bc)
用于检查整个数字,而不仅仅是最后一位数字。
Keep in mind that this may be affected by the actions of sprintf()
rather than the real accuracy of doubles (I don't think so personally since it had no troubles with certain numbers up to 2143
).
这是我写的测试程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
FILE *fin;
double d = 3.0; // 2^n + 1 to avoid exact powers of 2.
int i = 1;
char ds[1000];
char tst[1000];
// Loop forever, rely on break to finish.
while (1) {
// Get C version of the double.
sprintf (ds, "%.0f", d);
// Get bc version of the double.
sprintf (tst, "echo '2^%d - 1' | bc >tmpfile", i);
system(tst);
fin = fopen ("tmpfile", "r");
fgets (tst, sizeof (tst), fin);
fclose (fin);
tst[strlen (tst) - 1] = '\0';
// Check them.
if (strcmp (ds, tst) != 0) {
printf( "2^%d + 1 <-- bc failure\n", i);
printf( " got [%s]\n", ds);
printf( " expected [%s]\n", tst);
break;
}
// Output for status then move to next.
printf( "2^%d + 1 = %s\n", i, ds);
d = (d - 1) * 2 + 1; // Again, 2^n + 1.
i++;
}
}
这一直持续到:
2^49 + 1 = 562949953421313
2^50 + 1 = 1125899906842625
2^51 + 1 = 2251799813685249
2^52 + 1 = 4503599627370497
2^53 + 1 <-- bc failure
got [9007199254740992]
expected [9007199254740993]
这是roughly关于我预计它会失败的地方。
As an aside, I originally used numbers of the form 2n
but that got me all the way up to:
2^136 = 87112285931760246646623899502532662132736
2^137 = 174224571863520493293247799005065324265472
2^138 = 348449143727040986586495598010130648530944
2^139 = 696898287454081973172991196020261297061888
2^140 = 1393796574908163946345982392040522594123776
2^141 = 2787593149816327892691964784081045188247552
2^142 = 5575186299632655785383929568162090376495104
2^143 <-- bc failure
got [11150372599265311570767859136324180752990210]
expected [11150372599265311570767859136324180752990208]
with the size of a double being 8 bytes (checked with sizeof
). It turned out these numbers were of the binary form 1000...000
, which can be represented for far longer with doubles. That's when I switched to using 2n + 1
to get a better bit pattern (one at the start and one at the end).
现在,要明确的是,most可靠的方法是检查每个数字,看看哪个数字首先失败,但这将需要相当长的运行时间。考虑到 IEEE-754 编码的知识,这种方法是最好的方法。