7

次の式があるとします。

byte A = 69;
int B = 123;
long C = 3210;
float D = 4.9f;
double E = 11.11;

double X = (B * 100) + 338.1 - (E / B) / C;
double X1 = (B * 100) + (A * D) - (E / B) / C;

// JAVA - lost precision
System.out.println(X);  // 12638.099971861307
System.out.println(X1); // 12638.099581236307

// C# - almost the same
Console.WriteLine(X);  // 12638.0999718613
Console.WriteLine(X1)  // 12638.0999784417

Java は X から精度を失うことに気付きました。338.1 は暗黙の double ですが、C# はほとんどそうではありません。338.1 は float と double で等しいため、その理由がわかりません。ドットの後の数字は 1 つだけです。

4

2 に答える 2

1

Java では(B * 100) + (A * D)、float になります。12638.1 に最も近いフロートになります。ただし、12638 を 2 進数で表すには、最初の 1 を含めて 14 桁が必要です。これにより、小数部分を表す仮数の 10 桁が残ります。したがって、1024 分の 0.1 に最も近い数、つまり 102/1024 が得られます。これは 0.099609375 であることが判明したため、浮動小数点数には 0.000390625 の丸め誤差があります。

これが、Java プログラムで得られる X と X1 の違いのようです。

残念ながら、私は C# の専門家ではないので、なぜ C# が異なるのかを説明することはできません。

于 2013-10-17T10:23:33.923 に答える
0

これは、式のコンパイラの解釈に関係しています。中間の型変換を指定していないため、コンパイラは、A * D予想される逆ではなく、最初に型変換を実行してから乗算を実行します。これは奇妙な結果のように思えるかもしれませんが、面倒な型変換を指定しなくても、コンパイラがより正確な結果を提供する方法です。

Java はこれを処理しません。また、と a(B * 100) + (A * D)の乗算も同様に処理され、結果として. これは、次のように C# でシミュレートできます。intfloatfloat

double X2 = (float)((B * 100) + (A * D)) - (E / B) / C;
Console.WriteLine("X2: {0}", X2);

これは、高レベル コンパイラの利点の 1 つです (またはおそらく欠点と言う人もいるでしょう)。

于 2013-10-17T11:24:08.370 に答える