一般的な仮定は、1 / x * x == 1
. 一般的な IEEE 754 準拠のハードウェアでこれを破る最小の正の整数は?
乗法逆数の仮定が失敗すると、下手に書かれた有理数演算は機能しなくなります。C や C++ を含む多くの言語はデフォルトで浮動小数点数をゼロへの丸めを使用して整数に変換するため、小さなエラーでも整数の結果が 1 ずれることがあります。
簡単なテスト プログラムでは、さまざまな結果が得られます。
#include <iostream>
int main () {
{
double n;
for ( n = 2; 1 / n * n == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
for ( ; (int) ( 1 / n * n ) == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
}
{
float n;
for ( n = 2; 1 / n * n == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
for ( ; (int) ( 1 / n * n ) == 1; ++ n ) ;
std::cout << n << " (" << 1 - 1/n*n << ")\n";
}
}
GCC 4.3.4 を使用した ideone.com での結果は次のとおりです。
41 (5.42101e-20)
45 (5.42101e-20)
41 (5.42101e-20)
45 (5.42101e-20)
GCC 4.5.1 を使用しても同じ結果が得られますが、エラー マージンは正確にゼロであると報告されています。
私のマシン (GCC 4.7.2 または Clang 4.1) では、結果は次のようになります。
49 (1.11022e-16)
49 (1.11022e-16)
41 (5.96046e-08)
41 (5.96046e-08)
これは、--fast-math
オプションに関係なくです。使うと-mfpmath=387
驚くほど
41 (5.42101e-20)
41 (5.42101e-20)
41 (5.42101e-20)
41 (5.42101e-20)
値 5×10 -20は、64 ビット仮数に対応するイプシロン、つまり Intel 80 ビット拡張精度を使用した内部計算を暗示しているようです。
これは、FPU ハードウェアに大きく依存しているようです。テストに適した信頼できる値はありますか?
注: 言語標準やコンパイラが浮動小数点数システムについて何を保証しているかは気にしませんが、一般的なプログラミング システムには多くの意味のある保証があるとは思いません。数値と実世界のコンピューターとの相互作用について疑問に思っています。