什么是第一个双倍偏离相应的长三角?

我想知道从0d向上的第一个双重偏离“相同值”的长度偏离一些增量,比如1e-8。 我虽然失败了。 我试图在C中做这个,虽然我通常使用托管语言,以防万一。 请帮忙。

#include  #include  #define DELTA 1e-8 int main() { double d = 0; // checked, the literal is fine long i; for (i = 0L; i  DELTA || di < -DELTA) { printf("%f", d); break; } } } 

我猜测问题是di将我加倍并且因此d == i然后差异总是为0.我还能如何正确地检测到这一点 – 我更喜欢有趣的C铸造而不是比较字符串,这会永远。

答案 :完全符合我们的预期。 根据标准C / UNIX / POSIX工具,2 ^ 53 + 1 = 9007199254740993是第一个不同点。 非常感谢pax对他的节目。 我猜数学再次获胜。

IEE754中的双精度具有52位的精度,这意味着它们可以精确地存储数字(至少)2 51

如果你的long是32位,它们只有(正)范围0到2 31,所以没有32位长,不能完全表示为double。 对于64位长,它将(大致)为2 52,所以我将在那里开始,而不是零。

您可以使用以下程序来检测故障开始的位置。 在早期版本中,我依赖于这样一个事实:数字中的最后一个数字连续加倍,遵循序列{2,4,8,6}。 但是,我最终选择使用已知的可信工具(bc)来检查整数,而不仅仅是最后一位数。

请记住,这可能会受到sprintf()的操作的影响而不是双打的真实准确性(我不这么认为,因为它对于某些数字而言没有任何问题,最多可达到2 143 )。

这是该计划:

 #include  #include  int main() { FILE *fin; double d = 1.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^51 - 1 = 2251799813685247 2^52 - 1 = 4503599627370495 2^53 - 1 = 9007199254740991 2^54 - 1 <-- bc failure got [18014398509481984] expected [18014398509481983] 

这是关于我预期失败的地方。

顺便说一句,我最初使用2 nforms的数字,但这让我了解:

 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] 

double的大小是8个字节(用sizeof检查)。 事实certificate,这些数字是二进制forms"1000..." ,可以用双倍表示更长的时间。 那是当我切换到使用2 n -1来获得更好的位模式时:所有的一位。

当施放到双精灵时,第一个长度为’错误’将不会被1e-8关闭,它将被关闭1.只要双精度符合其有效位数的长度,它就能准确地表示它。

我确切地忘记了double对于精度与偏移有多少位,但这会告诉你它可以表示的最大尺寸。 第一个长的错误应该是二进制forms10000 …,所以你可以通过从1开始和左移来更快地找到它。

维基百科在有效数字中表示52位,不包括隐含的起始1.这应该意味着第一个长期被转换为不同的值是2 ^ 53。

虽然我在这次讨论中提到Fortran 95和后继者时犹豫不决,但我会提到Fortran自1990年标准以来提供了一个SPACING内在函数,它告诉你可表示REAL之间的差异是关于给定的REAL。 您可以对此进行二进制搜索,在SPACING(X)> DELTA时停止。 对于使用与您感兴趣的浮点模型相同的编译器(可能是IEEE754标准),您应该得到相同的结果。

在手边,我认为双打可以完全代表所有整数(在他们的范围内)。

如果情况并非如此,那么你将要把i和d都投射到比其中任何一个更精确的东西。 也许一个长的双重将起作用。