合計演算で順序を変更すると、異なる結果になることがありますか?

和演算で順序を変更すると、異なる結果が生じる可能性がありますか?

1. 概要

この簡単な記事では、合計の順序を変更すると異なる結果が返される理由を見ていきます。

2. 問題

次のコードを見ると、正しい答えを簡単に予測できます(13.22 4.88 21.45 = 39.55)。 私たちにとって簡単なことは、Javaコンパイラによって異なって解釈される可能性があります。

double a = 13.22;
double b = 4.88;
double c = 21.45;

double abc = a + b + c;
System.out.println("a + b + c = " + abc); // Outputs: a + b + c = 39.55

double acb = a + c + b;
System.out.println("a + c + b = " + acb); // Outputs: a + c + b = 39.550000000000004

数学的な観点から、合計の順序を変更しても常に同じ結果が得られます。

(A + B)+ C =(A + C)+ B

これは事実であり、整数のJava(および他のコンピュータープログラミング言語)でうまく機能します。 ただし、ほとんどすべてのCPUは非整数IEEE 754 binary floating point standardを使用するため、10進数が2進数として格納されると不正確になります。 コンピューターはすべての実数を正確に表すことはできません。

順序を変更すると、メモリに保存されている中間値も変更されるため、結果が異なる場合があります。 次の例では、単純にA + BまたはA + Cの合計で開始します。

double ab = 18.1; // = 13.22 + 4.88
double ac = 34.67; // = 13.22 + 21.45
double sum_ab_c = ab + c;
double sum_ac_b = ac + b;
System.out.println("ab + c = " + sum_ab_c); // Outputs: 39.55
System.out.println("ac + b = " + sum_ac_b); // Outputs: 39.550000000000004

3. 溶液

浮動小数点数の悪名が高いため、正確な値にはdoubleを使用しないでください。 これには通貨が含まれます。 正確な値を得るには、BigDecimalクラスを使用できます。

BigDecimal d = new BigDecimal(String.valueOf(a));
BigDecimal e = new BigDecimal(String.valueOf(b));
BigDecimal f = new BigDecimal(String.valueOf(c));

BigDecimal def = d.add(e).add(f);
BigDecimal dfe = d.add(f).add(e);

System.out.println("d + e + f = " + def); // Outputs: 39.55
System.out.println("d + f + e = " + dfe); // Outputs: 39.55

両方のケースで結果が同じであることがわかります。

4. 結論

10進数値を使用する場合、浮動小数点数が正しく表現されないことを常に覚えておく必要があります。これは、予期しない望ましくない結果を引き起こす可能性があります。 精度が必要な場合は、BigDecimalクラスを使用する必要があります。

いつものように、記事全体で使用されているコードはover on GitHubにあります。