27 votes

Arrondi des valeurs doubles en C #

Je veux une méthode d'arrondi sur le double des valeurs dans C#. Il doit être en mesure de ronde, d'un double de la valeur à toute l'arrondissement valeur de précision. Mon code sous la main ressemble à:

public static double RoundI(double number, double roundingInterval) {

    if (roundingInterval == 0.0)
    {
        return;
    }

    double intv = Math.Abs(roundingInterval);
    double sign = Math.Sign(number);
    double val = Math.Abs(number);

    double valIntvRatio = val / intv;
    double k = Math.Floor(valIntvRatio);
    double m = valIntvRatio - k;

    bool mGreaterThanMidPoint = ((m - 0.5) >= 1e-14) ? true : false;
    bool mInMidpoint = (Math.Abs(m - 0.5) < 1e-14) ? true : false;
    return (mGreaterThanMidPoint || mInMidpoint) ? sign * ((k + 1) * intv) : sign * (k * intv);
}

Donc RoundI(100, 3), devraient permettre de 99 et RoundI(1.2345, 0.001) devrait donner 1.235.

Le problème est, RoundI(1.275, 0.01) renvoie 1.27, plutôt que de 1.28. C'est parce que lors de l'exécution de double valIntvRatio = val/intv, qui est, à double valIntvRatio = 1.275 / 0.01, il donne 0.12749999999999. Je sais que c'est un problème avec la double représentation dans tout langage de programmation. Ma question est, est-il un code standard pour faire des choses comme cela, sans avoir à vous soucier de la précision sur le double? Ici, je mis la tolérance à 1e-14, mais c'est trop limiter pour ce problème et je ne sais pas quelle est la bonne tolérance à définir. Merci pour toute aide.

35voto

Jimmy Points 35501

Exemple d'utilisation de decimal , comme l'a souligné Kibbee

 double d = 1.275;
Math.Round(d, 2);          // 1.27
Math.Round((decimal)d, 2); // 1.28 
 

3voto

Ace Mark Points 380
 double d = 1.2345;

Math.Round(d, 2);
 

le code ci-dessus devrait faire l'affaire.

2voto

Jonas Elfström Points 16453

Si vous avez réellement besoin d'utiliser double remplacez-le simplement ci-dessous et cela fonctionnera mais avec les problèmes de précision habituels de l'arithmétique binaire à virgule flottante.

Il y a très certainement une meilleure façon de mettre en œuvre le "rounding" (presque une sorte d'arrondi de banquier) que ma corde jonglant ci-dessous.

 public static decimal RoundI(decimal number, decimal roundingInterval)
{
   if (roundingInterval == 0) { return 0;}

   decimal intv = Math.Abs(roundingInterval);
   decimal modulo = number % intv;
   if ((intv - modulo) == modulo) {
       var temp = (number - modulo).ToString("#.##################");
       if (temp.Length != 0 && temp[temp.Length - 1] % 2 == 0) modulo *= -1;
   }
    else if ((intv - modulo) < modulo)
        modulo = (intv - modulo);
    else
        modulo *= -1;

    return number + modulo;
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X