C/C++ の場合と同様に、 のような最小の表現可能な値であるという定義を使用して、Java でdouble
マシンのイプシロンを決定しようとしています。ウィキペディアによると、このマシンのイプシロンは(52 は仮数ビット数 - 1)と等しくなります。double
x
1.0 + x != 1.0
2^-52
double
私の実装では次のMath.ulp()
関数を使用します。
double eps = Math.ulp(1.0);
System.out.println("eps = " + eps);
System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));
結果は私が期待したものです:
eps = 2.220446049250313E-16
eps == 2^-52? true
ここまでは順調ですね。ただし、与えられたeps
が実際にそのような最小 であることを確認すると、より小さいもの、別名による前の値があるようです:x
1.0 + x != 1.0
double
Math.nextAfter()
double epsPred = Math.nextAfter(eps, Double.NEGATIVE_INFINITY);
System.out.println("epsPred = " + epsPred);
System.out.println("epsPred < eps? " + (epsPred < eps));
System.out.println("1.0 + epsPred == 1.0? " + (1.0 + epsPred == 1.0));
どちらが得られますか:
epsPred = 2.2204460492503128E-16
epsPred < eps? true
1.0 + epsPred == 1.0? false
ご覧のとおり、定義に反して、1 に追加すると 1 にならないマシン イプシロンよりも小さいものがあります。
では、この定義による一般的に受け入れられているマシン イプシロンの値のどこが間違っているのでしょうか? それとも私は何かを逃しましたか?浮動小数点演算の別の難解な側面を疑っていますが、どこが間違っていたのかわかりません...
編集:コメント者のおかげで、私はついにそれを手に入れました。私は実際に間違った定義を使用しました! eps = Math.ulp(1.0)
は、表現可能な最小の double > までの距離を計算しますが、それ1.0
がポイントです。それはで最小でeps
はなく、その値の約2 倍です。x
1.0 + x != 1.0
1.0 + Math.nextAfter(eps/2)
1.0 + eps