このメソッドは「true」を返します。なんで ?
public static boolean f() {
double val = Double.MAX_VALUE/10;
double save = val;
for (int i = 1; i < 1000; i++) {
val -= i;
}
return (val == save);
}
このメソッドは「true」を返します。なんで ?
public static boolean f() {
double val = Double.MAX_VALUE/10;
double save = val;
for (int i = 1; i < 1000; i++) {
val -= i;
}
return (val == save);
}
大きな値から非常に小さな値(1000未満)を減算しています。小さい値は大きい値よりもはるかに小さいため、理論結果に最も近い表現可能な値は元の値のままです。
基本的に、これは浮動小数点数の動作の結果です。
仮数に有効数字5桁と、0〜1000の範囲の指数のみを格納する10進浮動小数点型(簡単にするため)があるとします。
あなたの例は、10 999-1000と書くようなものです...有効数字5桁に丸めた場合、その結果がどうなるかを考えてください。はい、正確な結果は99999 ..... 9000(999桁)ですが、有効数字5桁の値しか表現できない場合、最も近い結果は10999になります。
Double.MAX_VALUE / 10に設定valすると、ほぼ等しい値に設定され1.7976931348623158 * 10^307ます。そこから1000のような値を差し引くと、二重表現の精度が必要になりますが、これは不可能であるため、基本的にはval変更されません。
必要に応じて、BigDecimalの代わりに使用できますdouble。
Double.MAX_VALUE非常に大きいため、JVMはそれとの違いを認識しませんDouble.MAX_VALUE-1000
結果から「1.9958403095347198E292」よりも小さい数を引くと、Double.MAV_VALUEまだDouble.MAX_VALUEです。
System.out.println(
new BigDecimal(Double.MAX_VALUE).equals( new BigDecimal(
Double.MAX_VALUE - 2.E291) )
);
System.out.println(
new BigDecimal(Double.MAX_VALUE).equals( new BigDecimal(
Double.MAX_VALUE - 2.E292) )
);
Ouptup:
true
false
Double.MAX_VALUEは1または1000に比べて膨大な数です。Double.MAX_VALUE-1通常、はに等しくなりDouble.MAX_VALUEます。したがって、1または1000をに減算しても、コードは大まかに何もしませんDouble.MAX_VALUE/10。常に覚えておいてください:
doublesまたはfloatsは実数の単なる近似であり、実数間で均等に分散されていない単なる有理数です。double近くにないsまたはsの間で非常に注意深く算術演算子を使用する必要floatがあります(このような他の多くのルールがあります...)doublesを使用しないでください。またはfloat、任意精度が必要な場合は、doubleには、試行している計算を実行するのに十分な精度がありません。したがって、結果は初期値と同じになります。
==オペレーターとは何の関係もありません。
valは大きな数であり、そこから減算1(または1000)すると、結果を値として正しく表現できませんdouble。無制限の数を表すために限られた数のビットしかないため、この数の表現はx同じx-1です。double
浮動小数点計算の結果は、正確な答えに最も近い表現可能な値です。このプログラム:
public class Test {
public static void main(String[] args) throws Exception {
double val = Double.MAX_VALUE/10;
System.out.println(val);
System.out.println(Math.nextAfter(val, 0));
}
}
プリント:
1.7976931348623158E307
1.7976931348623155E307
これらの数値の最初は、元の値です。2番目はそれよりも小さい最大のダブルです。
1.7976931348623158E307から1000を引くと、正確な答えはこれら2つの数値の間にありますが、1.7976931348623155E307よりも1.7976931348623158E307に非常に近いため、結果は1.7976931348623155E307に丸められ、valは変更されません。
doubleは浮動小数点数値型であり、数値を概算する方法であるためです。浮動小数点表現は数値をエンコードするため、通常よりもはるかに大きい数値または小さい数値を格納できます。ただし、指定されたスペースですべての数値を表すことができるわけではないため、複数の数値は同じ浮動小数点値に丸められます。
簡単な例として、通常は-10から10しか格納できない小さなスペースに、-1000から1000の範囲の値を格納できるようにしたい場合があります。したがって、すべての値を1000の位に丸めることができます。 -1000はとしてエンコードされ-10、-900はとしてエンコードされ-9、1000はとしてエンコードされ10ます。しかし、-999を保存したい場合はどうなりますか?エンコードできる最も近い値は-1000であるため、-999を-1000と同じ値としてエンコードする必要があります-10。
実際には、浮動小数点スキームは上記の例よりもはるかに複雑ですが、概念は似ています。数値の浮動小数点表現は、可能なすべての数値の一部しか表現できないため、スキームの一部として表現できない数値がある場合は、最も近い表現可能な値に丸める必要があります。
コードでは、1000以内のすべての値がDouble.MAX_VALUE / 10自動的にに丸められます。Double.MAX_VALUE / 10これが、コンピューターが考える理由(Double.MAX_VALUE / 10) - 1000 == Double.MAX_VALUE / 10です。