質問
に応じてドキュメンテーション、 decimal.Round
法を新たにラウンドにもアルゴリズムではない普通のエンベロープに従います。常にやりがいを終文書のカスタム機能により自然なラウンド半までアルゴリズム
public static decimal RoundHalfUp(this decimal d, int decimals)
{
if (decimals < 0)
{
throw new ArgumentException("The decimals must be non-negative",
"decimals");
}
decimal multiplier = (decimal)Math.Pow(10, decimals);
decimal number = d * multiplier;
if (decimal.Truncate(number) < number)
{
number += 0.5m;
}
return decimal.Round(number) / multiplier;
}
なんかここの枠組みのデザインを決定するのか
はありませ内蔵の実施の半までのアルゴリズムにさせていただきます。またはもしかしたポWindows API?
この誤解を招く恐れがある初心者のための単なる書 decimal.Round(2.5m, 0)
期待3その結果が2です。
解決
そのより良いアルゴリズムです。の多くのroundingsを行い、平均すべての.5末までの丸めを均等にします。これにより推計の実際の結果の場合はインスタンス、バンチの丸います。というものではない何かが、あるんじゃないでしょうか、正しいことだと思います。
他のヒント
他の回答には、Bankerのアルゴリズムの理由(別名半分から偶数まで)正しい選択は非常に正しいです。 ゼロから半分ほど離れたメソッドほど、マイナスまたはプラスのバイアスに悩まされることはありません。最も合理的な分布にわたって。
しかし、問題は、.NETがBankerの実際の丸めをデフォルトとして使用する理由であり、その答えは、Microsoftが IEEE 754 標準。これは、 Math.RoundのMSDN にも記載されています。備考。
また、.NETは、 MidpointRounding
列挙を提供することにより、IEEEによって指定された代替方法をサポートすることに注意してください。もちろん、関係を解決するためのより多くの代替手段を提供することもできますが、 IEEE標準を満たします。
「Microsoftの設計者がなぜこれをデフォルトとして選択したのですか?」という質問には答えられませんが、追加の機能は不要であることを指摘したいだけです。
Math.Round
では、 MidpointRounding
を指定できます。 a>:
- ToEven-数値が他の2つの値の中間にある場合、最も近い偶数に丸められます。
- AwayFromZero-数値が2つの中間にある場合、ゼロから離れた最も近い数値に向かって丸められます。
10進数は、主にお金に使用されます。 お金を扱う場合、銀行家の丸めは一般的です。または言うことができます。
それを必要とするのは主に銀行家です 小数型;したがって、 「銀行家の丸め」
銀行の丸めには、次の場合に平均して同じ結果が得られるという利点があります。
- 「請求書の行」のセットを追加する前に丸めます、
- またはそれらを合計して合計
合算する前に丸くすることで、コンピューターが登場する前の多くの作業を節約できました。
(英国では、小数銀行は半ペンスを処理しませんでしたが、長年の間、半ペンス硬貨がまだあり、店はしばしば半ペンスで終わる価格がありました-たくさんの丸め)
次のようなRound関数の別のオーバーロードを使用します。
decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)
3 が出力されます。使用する場合
decimal.Round(2.5m, 0,MidpointRounding.ToEven)
銀行家の丸めを取得します。
また、「丸め」も注意してください。フォーマット文字列(「0」など)を使用すると、「Math.Round()」とは異なる結果が生成されます。つまり、5、0.5などは常に切り上げられます。
let d, d' = 2.5, 3.5
Debug.WriteLine(Math.Round(d)) // 2.5 -> 2
Debug.WriteLine(d.ToString("0")) // 2.5 -> 3
Debug.WriteLine(Math.Round(d')) // 3.5 -> 4
Debug.WriteLine(d'.ToString("0")) // 3.5 -> 4
let dd, dd' = 2.25, 2.35
Debug.WriteLine(Math.Round(dd, 1)) // 2.25 -> 2.2
Debug.WriteLine(dd.ToString("0.0")) // 2.25 -> 2.3
Debug.WriteLine(Math.Round(dd', 1)) // 2.35 -> 2.4
Debug.WriteLine(dd'.ToString("0.0")) // 2.35 -> 2.4