なぜ私が次のことをすると...
Math.Round(0.75, 1, MidpointRounding.AwayFromZero)
私は0.8を得る
しかし、私が次のことをすると...
Math.Round(0.575, 2, MidpointRounding.AwayFromZero)
私は0.58を取得しません。代わりに、0.57 を取得します。5 以上は切り上げたいので、0.575 は 0.58 になるはずです。
なぜ私が次のことをすると...
Math.Round(0.75, 1, MidpointRounding.AwayFromZero)
私は0.8を得る
しかし、私が次のことをすると...
Math.Round(0.575, 2, MidpointRounding.AwayFromZero)
私は0.58を取得しません。代わりに、0.57 を取得します。5 以上は切り上げたいので、0.575 は 0.58 になるはずです。
問題は、0.575 を 2 進浮動小数点数 (例えば double) として正確に表すことができないことです。正確にはわかりませんが、最も近い表現はおそらく少し低いように思われるため、丸めの際に真の表現を使用して切り捨てます。
この問題を回避したい場合は、より適切なデータ型を使用してください。decimal
あなたが望むことをします:
Math.Round(0.575M, 2, MidpointRounding.AwayFromZero)
結果:0.58
0.75 が正しいことをする理由は、単純な 1/2 + 1/4 (つまり 2^-1 +2^-2) であるため、2 進浮動小数点で表現するのが簡単だからです。一般に、2 の累乗の有限和は、2 進浮動小数点で表すことができます。例外は、2 の累乗が範囲が広すぎる場合です (たとえば、2^100+2 は正確に表現できません)。
編集して追加:
C# での出力の double の書式設定は、0.575 が実際には 0.575 ではないことを理解するのが非常に難しい理由を理解する上で興味深いかもしれません。受け入れられた回答の DoubleConverter は、0.575 が正確な文字列である0.5749999999999999555910790149937383830547332763671875
ことを示します。このことから、丸めによって 0.57 が得られる理由がわかります。
このSystem.Math.Round
方法ではDouble
、他の人が指摘しているように、浮動小数点の精度エラーが発生しやすい構造を使用します。この問題に遭遇したときに見つけた簡単な解決策System.Decimal.Round
は、同じ問題が発生せず、変数を小数として再定義する必要がないメソッドを使用することでした。
Decimal.Round(0.575, 2, MidpointRounding.AwayFromZero)
結果:0.58
これは、倍精度/小数の精度が不足しているために発生します (つまり、関数が常に期待どおりの結果を返すとは限りません)。
次のリンクを参照してください: MSDN on Math.Round
関連する引用は次のとおりです。
10 進数値を浮動小数点数として表現したり、浮動小数点値に対して算術演算を実行したりすると、精度が失われる可能性があるため、場合によっては、Round(Double, Int32, MidpointRounding) メソッドが指定されたとおりに中間値を丸めないように見えることがあります。これは、2.135 が 2.14 ではなく 2.13 に丸められる次の例に示されています。