16

Microsoft SQL Server Express 2016 を使用してストアド プロシージャを作成しています。要件の 1 つは、丸めを行うことです。しかし、時々、丸めが間違っています。T-SQL の丸めは C# とまったく同じではないことがわかりましたが、なぜですか?

以下の 2 つの丸めを比較します。

In T-SQL: ROUND(0.045, 2) --> this will produce 0.05

In C#: Math.Round(0.045, 2) --> this will produce 0.04

なぜ C# は 0.04 を生成するのですか? 0.05じゃないの?

C# の丸め = T-SQL の丸めを行うにはどうすればよいですか?


好奇心から、C# でこれを試しました。

Math.Round(0.055, 2)

C# が何に丸められたと思いますか? 0.06に丸めました!今、私は完全に混乱しています!

Math.Round(0.045, 2)   // This becomes 0.04
Math.Round(0.055, 2)   // This becomes 0.06

説明は何ですか?

4

3 に答える 3

21

これは、SQL が「AwayFromZero」を使用するのに対し、.NET はデフォルトで「ToEven」丸めを使用するためです。これを参照してください。これらは異なる丸め方法であり、5 の処理方法が異なります。

AwayFromZero は、次の正の数に丸めるか、次の負の数に丸めます。つまり、0.5 は 1 になり、-0.5 は -1 になります。ToEven は最も近い偶数に丸めます。したがって、2.5 は 2 になり、3.5 は 4 になります (負の数についても同様です)。5 以外の数値も同様に扱われ、最も近い数値に丸められます。5 は 2 つの数字から等距離にあるため、戦略が異なる特殊なケースです。

ToEven は「バンキング ルール」とも呼ばれ、IEEE_754で使用される既定値です。これが.NET の既定値である理由です。

逆に、AwayFromZero は「コマーシャル ラウンド」とも呼ばれます。なぜこれが SQL Server のデフォルトなのかはわかりません。おそらく、これが最も広く知られ、理解されている方法だからです。

もちろん、必要なものはいつでも設定できます。

C# では、次のことができます。

Math.Round(value, MidpointRounding.ToEven)

また

Math.Round(value, MidpointRounding.AwayFromZero)

SQL では、 ROUND()FLOOR()および/またはCEILING()を使用できます。

どちらの方法が優れているかは、それを何に使用するか、何を望んでいるかによって異なります。合理的なコレクション/配布の場合、丸められた toEven 値の平均は、元の値と同じになります。これは、AwayFromZero では必ずしも当てはまりません。多くの.5データを含むコレクションがある場合、AwayFromZero を丸めると、それらの値がすべて同じように扱われ、バイアスが導入されます。

その結果、丸められた値の平均は元の値の平均と同じではなくなります。丸めのポイントは、同じ意味を保持しながら、値を単純にすることです。平均が一致しない場合、これは当てはまりません。丸められた値は、元の値とは (わずかに?) 異なる意味を持ちます。

于 2017-01-11T13:51:25.717 に答える