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?
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
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.