IEE754 の double の精度は 52 ビットです。これは、(少なくとも) 2 51までの数値を正確に格納できることを意味します。
long が 32 ビットの場合、0 から 2 31までの (正の) 範囲しか持たないため、double として正確に表現できない 32 ビット long はありません。64 ビットの長さの場合、(おおよそ) 2 52になるので、ゼロではなく、そのあたりから開始します。
次のプログラムを使用して、障害が発生し始めた場所を検出できます。以前のバージョンでは、連続して 2 倍になる数の最後の桁は {2,4,8,6} のシーケンスに従うという事実に依存していました。しかし、最終的には(bc)
、最後の桁だけでなく数字全体をチェックするために、既知の信頼できるツールを使用することにしました。
これは double の実際の精度ではなく、アクションの影響を受ける可能性があることに注意してください (2 143sprintf()
までの特定の数値で問題がなかったので、個人的にはそうは思いません)。
これはプログラムです:
#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 nの形式の数値を使用していましたが、次のようになりました。
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
)。"1000..."
これらの数値は、2 進数ではるかに長く表現できる2 進数形式であることが判明しました。そこで、より良いビット パターン (すべて 1 ビット) を得るために2 n -1の使用に切り替えました。