web-dev-qa-db-fra.com

float / double Math.Round en C #

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);

premier: 31,1

drst: 31.2

Quelqu'un peut-il expliquer pourquoi?

18
Yaoqing

Eh bien, Math.Round Veut double, pas float, c'est pourquoi

Math.Round(ff, 1, MidpointRounding.AwayFromZero);

est égal à

Math.Round((double)ff, 1, MidpointRounding.AwayFromZero);

et si nous inspectons la valeur de (double)ff

Console.Write(((double)ff).ToString("R"));

nous verrons arrondir les erreurs en action

31.149999618530273

Enfin, Math.Round(31.149999618530273, 1, MidpointRounding.AwayFromZero) == 31.1 comme prévu

27
Dmitry Bychenko

En virgule flottante, tous les nombres sont représentés en interne sous forme de fractions où le dénominateur est une puissance de 2.

(C'est une manière similaire à la façon dont les décimales sont en fait des fractions avec des dénominateurs de puissance de 10. Donc 31.15 n'est qu'un moyen d'écrire la fraction 3115/100)

En virgule flottante, 31.15 doit être représenté en interne sous la forme d'un nombre binaire. La fraction binaire la plus proche est: 1111.1001001100110011001100110011001100110011001100110011001100...repeating

Le 1100 se reproduit (se répète pour toujours), et donc le nombre sera tronqué selon qu'il est stocké dans un double ou un flottant. Dans un flotteur, il est tronqué à 24 chiffres et dans un double à 53.

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

Par conséquent, vous pouvez voir que le double vers lequel ce nombre se convertit est en fait légèrement plus grand que le flotteur vers lequel il se convertit. Il est donc clair qu'il ne sera pas nécessairement arrondi au même nombre, car ce n'est pas le même nombre pour commencer.

13
Ben