.NETがデフォルトで銀行の丸めを使用するのはなぜですか?


271

ドキュメントによると、この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を得る初心者には誤解を招く可能性があります。


105
切り上げは「より自然」ではありません。自然はそれとは何の関係もありません。それは単に「丸め」の概念を学んだときに小学校で学んだことです。小学校のレッスンは、常に全体像を描くとは限りません。
ロブ・ケネディ

45
@Robそして、それが正しくないにもかかわらず、それがより自然な理由です
Pacerier

10
わかりません、@ Pacerier。私はなぜそれ自然ではないのかを説明しました、そしてあなたはそれ実際に自然な理由であると言います。私の議論はあなたの反対である私の結論に対してどのように機能しますか?慣れてきているものは自然に感じられるかもしれませんが、「第二の性質」だと比喩的に言うこともありますが、それでは自然にはなりません。
Rob Kennedy

16
@ロブそれは自然に感じるので、それは自然だと言っています。あなたは、同じ変数名を持つ36個の異なるオブジェクトがあることを知っています自然の権利は?
Pacerier、2011年

9
自然は完全に類似しているため、使用するのは間違った言葉です。しかし、これは奇妙なことです。たぶん「通常」のほうがいい言葉でしょう。「0.5人々が行う通常の丸めは何
ですか

回答:


196

おそらくそれがより良いアルゴリズムだからです。実行される多くの丸めの過程で、すべての.5の端数が均等に切り上げおよび切り下げされることを平均化します。これにより、たとえば、丸められた数値の束を追加する場合などに、実際の結果をより正確に推定できます。一部の人が期待するものではないかもしれませんが、おそらくそれが正しい方法でしょう。


71
もちろん、奇数と偶数の入力のフラット分布があると仮定します
jk。

7
以下のための+1 より良いアルゴリズム、Ostemarはあるものの、実際の答え(stackoverflow.com/questions/311696/...
イアン・ボイド

2
@Ian、私もその答えを+1します。とにかく、「受け入れられた答えを動かす」ことができます。たぶん、OPはこれを行うことができます。この方法を使用する「理由」の実際の答えは、ページの半分ほどです。私は担当者のブーストがかなり好きですが、この回答から週に1回程度の回答を得ています。
Kibbee、2011

@Kibbee-私の答えを押し上げてくれてありがとう。彼が適切だと思うように、受け入れられた答えを変更するのはOPの責任だと思いますか?
オステマール2009

-1は、より優れたアルゴリズムであることを示します。-バンカーの丸めを使用してランダムな数のサンプルが与えられると、奇数の位置よりも偶数の位置でより多くの数を持つことになります。-元の分布と同様の広がりを再び得るのは、これらの数値を平均化した後でのみです。-ただし、たとえばこのデータを散布図にプロットする場合、人為的なグループ化が見られることがあります。
paul23

437

Bankerのアルゴリズム(別名:丸めから偶数まで)が適切な選択である理由と他の答えは非常に正しいです。それは、最も妥当な分布に対して、ゼロから丸い半分ほど負または正のバイアスの影響を受けません。

しかし、問題はなぜ.NETがBankerの実際の丸めをデフォルトとして使用するのかということでした-答えは、MicrosoftがIEEE 754標準に従っているということです。これは、MSDNのMath.Roundの「解説」にも記載されています。

また、.NETは、MidpointRounding列挙を提供することにより、IEEEによって指定された代替方法をサポートしていることにも注意してください。もちろん、提携を解決するより多くの選択肢を提供することもできますが、IEEE規格を満たすことだけを選択します。


17
では、なぜIEEE 754は銀行家の端数処理に従うのですか?この(まだ良い)答えはバケットを通過するだけです。
Henk Holterman 2013年

4
@HenkHoltermanおそらく他の回答で述べられているため(そして私が要約したように); これは、負または正のバイアスの影響をあまり受けないため、ほとんどのディストリビューションおよび問題のドメインで、より適切なデフォルトになります。
オステマール2013


IEEE 754は浮動小数点数の標準であり、Decimalはそうではないので、興味深いと思います。IEEE 754に準拠している場合があるため、DoubleをDecimalとして丸めるために同じアルゴリズムが使用されます。
Brandon Barkley、2016

1
@BrandonBarkley Decimalまたはdecimal 浮動小数点数であり、IEEE 754に10進浮動小数点数が含まれています。
Pablo H

88

「なぜマイクロソフトのデザイナーはこれをデフォルトとして選んだのですか?」という質問には答えられませんが、追加の機能は不要であることを指摘したいだけです。

Math.Roundを指定できますMidpointRounding

  • ToEven-他の2つの値の中間にある数値は、最も近い偶数に丸められます。
  • AwayFromZero-数値が他の2つの値の中間にある場合、ゼロから離れた最も近い数値に丸められます。

8
そして、関連するスレッドで述べたように、丸めが一貫していることを確認してください。データベースや.netで丸めを行うと、奇妙な1セントのエラーが発生し、何週間もかかることになります。見つけ出す。
クリス

59
あるクライアントが40,000ドル以上を支払って、両方とも10億ドルをためらった2つの数値間の$ 0.11丸め誤差を追跡しました。$ 0.11は、メインフレームとSQL Serverの間の8桁目の丸め誤差の違いによるものです。完璧主義者について話してください!
EJブレナン

12
@EJB-10億ドルを扱っていれば、おそらく完璧主義者になるでしょう;-)
royse41

12
@EJ Brennan:それを理解するのに4万ドルかかった?このような問題が常に発生します。丸めが原因#1、ダブル/フロートの正規化が原因#2、事前定義されたテストケースがない場合、プログラマエラー#3-#3がすぐに#1に設定される可能性があります。ところで、億万長者のクライアントに連絡してください。彼のシステムにも$ 40kのバグがいくつか見つかると思います。:D

3
@seanxe:または、Office Spaceを見た場合。真剣に、あなたがお金の神秘的で小さな不正確さを目にするときはいつでも、それらがどのように起こっているのか正確に謎を解くことはほとんど常に良い考えです。バグを修正しないことを決定することは可能ですが、根本的な原因を知ることはまだ価値があります。お金を扱う多くの人は、ほんのわずかな不正確さにも気づいて喜んでいるに違いない。
ブライアン

22

小数は主にお金に使用されますお金を扱う場合、銀行員の丸めは一般的です。または言うことができます。

小数型を必要とするのは主に銀行家です。したがって、「銀行の丸め」を行います

バンカーの丸めには、次の場合に平均して同じ結果が得られるという利点があります。

  • 追加する前に、「請求書ライン」のセットを丸めます。
  • またはそれらを合計してから合計を丸めます

合計する前の丸めにより、コンピュータが登場する前の多くの作業を節約できました。

(英国では、10進銀行がハーフペンスを扱っていませんでしたが、何年もの間、ハーフペンスのコインがあり、ショップはしばしば価格がハーフペンスで終わっていました。


8
「10進数は主にお金のために使われます」...そして、整数以外のすべてのもの。
John Tyree

3
@JohnTyree、真ではありません。ほとんどの場合、整数ではないときにdouble / floatが使用されます。stackoverflow.com/questions/2545567/…を
Ian Ringrose

3
ワオ。私のとんでもない間違い。Decmials、はい。小数、いいえ。後世のために、私はここの元の感情に同意します。
John Tyree

銀行員は銀行員の丸めを好むかもしれませんが、簿記係はそれのファンではないかもしれません、彼らはそれが奇数であるか偶数であるかどうかに関係なく、0.005の差は0.01で切り上げるべきであると言います。
JustAMartin 2016年

0

次のようなRound関数の別のオーバーロードを使用します。

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

3を出力します。そしてあなたが使うなら

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

あなたは銀行家の丸めを取得します。


4
これは、なぜ Banker's Roundingがデフォルトとして選択されたのという質問には答えません。
shortstuffsushi 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.