2016年9月28日水曜日

C#での四捨五入での落とし穴

C#で四捨五入をする際に、2つの落とし穴があります。
それは、四捨五入に失敗する問題と、もう一つは速度の問題です。


四捨五入に失敗

こうやると、四捨五入に失敗します。

Math.Round( 0.5  );

それは、Math.Roundは、デフォルトでは、「2 つの整数 (一方が偶数で、もう一方が奇数) の中間にある場合は、偶数が返されます。」からです。
そのため、上の関数を実行すると、0が返ります。
通常の四捨五入をするためには、引数の

MidpointRounding.AwayFromZero

を追加する必要があります。


四捨五入の速度

プログラムを書くときには、標準的な関数がある場合には、そちらを使ったほうが良いです。
でも、そうとも言えない場合もあります。
今回、四捨五入をするにあたり、[Math.Round]と、[0.5を加算後にInt32でキャスト]した場合の速度を比較しました。


static void Main( string[] args )
{
    var count = 10000;
    var val = new Decimal(0.5d);
    var st = new Stopwatch();
    st.Start();
    for( var i = 0; i < count; i++ )
    {
        Console.WriteLine( Math.Round( val + i, MidpointRounding.AwayFromZero ) );
    }
    st.Stop();
    var time1 = st.ElapsedMilliseconds;
    st.Reset();
    var add = new Decimal(0.5);
    st.Start();
    for( var i = 0; i < count; i++ )
    {
        Console.WriteLine( (Int32)(val + i + add) );
    }
    st.Stop();
    var time2 = st.ElapsedMilliseconds;
    Console.WriteLine();
    Console.WriteLine( time1 );
    Console.WriteLine( time2 );
}

結果は次の通りです。

5286
452
予想はしていましたが、少し驚きました。
繰り返し処理でなければ、あまり考慮する必要はないかもしれませんが、
繰り返し四捨五入する場合には、Int32でキャストしたほうが良いと思います。


0 件のコメント:

コメントを投稿