题
我想知道从0D向上第一双由长“相同的值”,由一些增量的偏离时,说1E-8。我虽然没有在这里。我试图做这在C虽然我通常使用管理语言,以防万一。请帮助。
#include <stdio.h>
#include <limits.h>
#define DELTA 1e-8
int main() {
double d = 0; // checked, the literal is fine
long i;
for (i = 0L; i < LONG_MAX; i++) {
d=i; // gcc does the cast right, i checked
if (d-i > DELTA || d-i < -DELTA) {
printf("%f", d);
break;
}
}
}
我猜测的问题是,迪蒙上我的两倍,因此d ==我再差始终为0怎么我还能检测到这种正确 - 我宁愿乐趣ç蒙上比较字符串,这将永远。
ANSWER :正是如我们预期。 2 ^ 53 + 1 = 9007199254740993是根据标准C / UNIX / POSIX工具的差的第一点。由于太多的PAX他的计划。我猜数学再次获胜。
解决方案
双打中IEE754具有52位的精度,这意味着它们能准确地存储号码到(至少)2 51
如果您的多头是32位,它们将只具有(正)范围为0〜2 31 所以没有32位长,不能精确地为双表示。对于一个64位长,这将是(大约)2 52 所以我会开始围绕那里,而不是在零。
可以使用下面的程序来检测其中的故障开始发生。一个早期版本我一直依靠,在一些连续加倍最后一个数字如下序列{2,4,8,6}的事实。然而,我最终选择使用已知的受信任的工具(bc)
检查的整数,而不仅仅是最后一位。
请记住,这的可以的由sprintf()
的行动,而不是双打的实际精度(我不这么认为,因为亲自它与某些数字没有烦恼高达2受到影响< SUP> 143 )。
这是该程序:
#include <stdio.h>
#include <string.h>
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 名词但让我到:
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]
用的双为8个字节大小(与sizeof
选中)。原来,这些数字都可以表示与双打长得二进制形式"1000..."
的。这时候我切换到使用2 名词 -1,以获得更好的位模式:全1
其他提示
转换为双时不会被1E-8是关闭的第一长为“错误”,它将被1被关闭只要双可以容纳在其有效数长,它将准确地表示它
我忘记了双到底有多少位对精度VS偏移,但会告诉你最大大小都可以表现。第一长是错应该有二进制形式10000 ......,这样你就可以找到它通过从1开始左移快得多。
维基说在有效数位52,不计算隐式的起始1.这应该意味着第一长要被转换为不同的值被2 ^ 53
虽然我不愿提及的Fortran 95和接班人,在这次讨论中,我会提到,Fortran语言自从1990标准提供了一个SPACING固有功能,它告诉你的可表示的REAL之间相差约一个给定的实什么。你可以做这个二进制搜索,间距(X)> DELTA时停止。对于使用相同的浮点模型作为一个你感兴趣的(可能是IEEE754标准),你应该得到相同的结果。编译器
副手,我觉得双打可以代表所有整数(其范围内)完全一样。
如果不是的话,那么你会希望i和d与比二者更精确投的东西。也许很长的双将工作。