丸め誤差について聞いたことがあるかもしれませんが、なぜここで丸め誤差があるのか疑問に思われるかもしれません。
float a1 = 1.4f;
float b1 = 0.5f;
double c1 = 1.4;
double d1 = 0.5;
System.out.println(new BigDecimal(a1) + " - " + new BigDecimal(b1) + " is " +
new BigDecimal(a1).subtract(new BigDecimal(b1)) + " or as a float is " + (a1 - b1));
System.out.println(new BigDecimal(c1) + " - " + new BigDecimal(d1) + " is " +
new BigDecimal(c1).subtract(new BigDecimal(d1)) + " or as a double is " + (c1 - d1));
プリント
1.39999997615814208984375 - 0.5 is 0.89999997615814208984375 or as a float is 0.9
1.399999999999999911182158029987476766109466552734375 - 0.5 is
0.899999999999999911182158029987476766109466552734375
or as a double is 0.8999999999999999
ご覧のとおり、これらの値を正確に表すことも、表すことfloat
もdouble
できません。floatまたはdoubleを出力すると、これを隠すために丸めが発生します。このfloatの場合、小数点以下7桁に丸めると、期待した数になります。16桁の精度を持つdoubleの場合、丸め誤差が表示されます。
@Eric Postpischilのように、float
ordouble
演算に丸め誤差があるかどうかは、使用される値に完全に依存することに注意してください。この状況では、表された値が2倍の値よりも0.9から離れていても、より正確であるように見えたのはフロートでした。
つまり、使用する場合、float
またはdouble
賢明な丸め戦略を使用する必要がある場合です。これができない場合は、BigDecimalを使用してください。
System.out.printf("a1 - b1 is %.2f%n", (a1 - b1));
System.out.printf("c1 - d1 is %.2f%n", (c1 - d1));
プリント
a1 - b1 is 0.90
c1 - d1 is 0.90
floatまたはdoubleを印刷する場合、最も近い10進数の短い値が本当に必要な値であると想定されます。つまり、0.5ulp以内です。
例えば
double d = 1.4 - 0.5;
float f = d;
System.out.println("d = " + d + " f = " + f);
プリント
d = 0.8999999999999999 f = 0.9