を使用してC#で10進値を丸めているときに問題に直面していますMath.Round(a, 2);
1.275 を小数点以下 2 桁で四捨五入すると、結果は 1.27 になります。1.375 に対して同じことをすると、結果は 1.38 になります。
1.275 を 1.28 に丸めないのはなぜですか?
ありがとう
を使用してC#で10進値を丸めているときに問題に直面していますMath.Round(a, 2);
1.275 を小数点以下 2 桁で四捨五入すると、結果は 1.27 になります。1.375 に対して同じことをすると、結果は 1.38 になります。
1.275 を 1.28 に丸めないのはなぜですか?
ありがとう
問題を再現できません:
Math.Round(1.275m, 2) => 1.28m
Math.Round(1.375m, 2) => 1.38m
値を使用しているというあなたの主張decimal
は誤りであり、double
代わりに値を使用していると思われます。double
多くの 10 進数値を正確に表すことはできないため、 と書く1.275
と、実際には 1.27499 になります...1.375
は数少ない表現可能な 1 回の 1 つなので、実際には1.375
.
コードで正確な 10 進数表現が重要な場合 (たとえば、お金を扱う場合)、やなどの 2 進浮動小数点ではなく、使用する必要があります。decimal
double
float
しかし、10 進数表現を使用しても、丸めは多くのユーザーにとって予期しない動作をします。
Math.Round(1.265m, 2) => 1.26m
Math.Round(1.275m, 2) => 1.28m
デフォルトでMath.Round
は、バンカーのラウンドMidpointRounding.ToEven
とも呼ばれる を使用します。これにより、常に で切り上げられることによるバイアスの蓄積が回避されます。.5
Round
丸めモードを取るのオーバーロードを使用し、それを に設定してAwayFromZero
、期待どおりの動作を得ることができます。
Math.Round(1.275m, 2, MidpointRounding.AwayFromZero) => 1.28m
MSDNは、この動作に関して次のように述べています。
発信者への注意事項
10 進数値を浮動小数点数として表現したり、浮動小数点値に対して算術演算を実行したりすると、精度が失われる可能性があるため、場合によっては、Round(Double, Int32) メソッドが中間値を最も近い偶数に丸めるように見えないことがあります。小数点以下桁数の値。これは、2.135 が 2.14 ではなく 2.13 に丸められる次の例に示されています。これは、メソッドが内部で value を 10桁で乗算するために発生し、この場合の乗算演算は精度の損失に悩まされます。
public class Example
{
public static void Main()
{
double[] values = { 2.125, 2.135, 2.145, 3.125, 3.135, 3.145 };
foreach (double value in values)
Console.WriteLine("{0} --> {1}", value, Math.Round(value, 2));
}
}
// The example displays the following output:
// 2.125 --> 2.12
// 2.135 --> 2.13
// 2.145 --> 2.14
// 3.125 --> 3.12
// 3.135 --> 3.14
// 3.145 --> 3.14
値があるDecimal
場合、正しく丸め1.275
られ1.28
ます。
値があるDouble
場合、値1.275
を正確に表すことができないため、同じようには動作しません。double
この値を使用する1.275
と、実際には正確な値よりもわずかに小さくなり1.275
ます1.2749999999999999
。
その値を四捨五入すると、正確に と の間1.27
ではなく1.28
、わずかに に近づくため1.27
、切り上げではなく切り捨てられます。
これはひどいハックですが、Format を使用してみてください。不可解なことに、私たち全員が慣れ親しんでいる丸めを使用しています。
Val(Format(2.25, "0.0")) returns 2.3
(また)
参考までに: .Net バージョン 2.0 から、"0.5 ケース" をパラメータ MidpointRounding で丸める方法を定義することが可能になりました。ToEven または AwayFromZero のいずれかです。したがって、「標準」の丸めは次のようになります。
Math.Round(2.25, 1, MidpointRounding.AwayFromZero);
これは、値「2.3」を返します。
これは、丸めが小数ではなく倍精度であるためです。
Console.WriteLine(Math.Round(1.275M, 2)); // outputs 1.28
Console.WriteLine(Math.Round(1.375M, 2)); // outputs 1.38
Decimal と double は大きく異なります
Format(1.275, "0.00"))
このブログのコメントで示唆されているように: http://weblogs.asp.net/sfurman/archive/2003/03/07/3537.aspx
どのバージョンの .Net フレームワークを使用していますか? 1.1 を超える場合は、midpointroundingを使用して、次のように設定できます。AwayFromZero
Math.Round(1.275, 2, MidpointRounding.AwayFromZero);
http://msdn.microsoft.com/en-us/library/9s0xa85y%28v=vs.110%29.aspx
ドキュメントに従って予想される動作。
たとえば、小数が 1 に等しい場合、.05 と .05000 はどちらも .1 と .2 の中間にあり、.1 は奇数であるため、2.15 と 2.15000 は両方とも 2.2 に丸められます。同様に、小数が 1 に等しい場合、.05 と .05000 はどちらも .0 と .1 の中間にあり、.0 は偶数であるため、2.05 と 2.05000 は両方とも 2.0 に丸められます。このメソッドの動作は、IEEE 規格 754 のセクション 4 に従います。中間値を一方向に一貫して丸めることに起因する丸め誤差を最小限に抑えます。Round(Decimal, Int32) メソッドで使用される丸めの種類を制御するには、Decimal.Round(Decimal, Int32, MidpointRounding) オーバーロードを呼び出します。
Decimal.Round(a, 2, MidpointRounding.AwayFromZero);