web-dev-qa-db-ja.com

C#のfloat / double Math.Round

float ff = (float)31.15;

double dd = 31.15;

var frst = Math.Round(ff, 1, MidpointRounding.AwayFromZero);

var drst = Math.Round(dd, 1, MidpointRounding.AwayFromZero);

frst:31.1

最初:31.2

誰かが理由を説明できますか?

18
Yaoqing

そうですね、_Math.Round_はdoubleではなくfloatを必要としています。そのため、

_Math.Round(ff, 1, MidpointRounding.AwayFromZero);
_

等しい

_Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);
_

そして、_(double)ff_値を検査すると

_Console.Write(((double)ff).ToString("R"));
_

丸めエラーが表示されます

_31.149999618530273
_

最後に、期待どおりMath.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1

27
Dmitry Bychenko

浮動小数点では、すべての数値は、分母が2の累乗である分数として内部的に表現されます。

(これは、小数が実際に10の累乗の分母を持つ分数であるのと同様の方法です。したがって、31.15は、分数を書くための方法です3115/100

浮動小数点では、31.15は、内部的に2進数として表現する必要があります。最も近い2進数は次のとおりです:1111.1001001100110011001100110011001100110011001100110011001100...repeating

1100繰り返します(永久に繰り返されます)。したがって、数値は、doubleに格納されているか、floatに格納されているかに応じて切り捨てられます。 floatでは24桁に切り捨てられ、doubleでは53桁に切り捨てられます。

Exact:  1111.100100110011001100110011001100110011001100110011001100110011001100...forever
Float:  1111.10010011001100110011
Double: 1111.1001001100110011001100110011001100110011001100110

したがって、この数値が変換するdoubleは、実際には変換するfloatよりわずかに大きいことがわかります。そもそも同じ数ではないため、必ずしも同じ数に丸められるわけではないことは明らかです。

13
Ben