2010-10-07 19 views
1

J'ai cette méthode statique, il reçoit un double et "coupe" sa queue fractionnaire en laissant deux chiffres après le point. fonctionne presque tout le temps. J'ai noté que quand il reçoit 2.3 il le tourne à 2.29. Cela n'arrive pas pour 0.3, 1.3, 3.3, 4.3 et 102.3. Code multiplie fondamentalement le nombre par 100 utilisations modf divise la valeur entière par 100 et le renvoie. Voici le code capture ce un numéro spécifique et imprime:modf renvoie 1 comme le fractionnaire:

static double dRound(double number) { 

    bool c = false; 
    if (number == 2.3) 
     c = true; 


    int factor = pow(10, 2); 
    number *= factor; 


    if (c) { 
     cout << " number *= factor : " << number << endl; 
     //number = 230;// When this is not marked as comment the code works well. 
    } 


    double returnVal; 
    if (c){ 
     cout << " fractional : " << modf(number, &returnVal) << endl; 
     cout << " integer : " <<returnVal << endl; 
    } 


    modf(number, &returnVal); 
    return returnVal/factor; 
} 

il imprime:

nombre * = facteur: 230

fraction: 1

entier: 229

Est-ce que quelqu'un sait pourquoi cela se produit et comment puis-je résoudre ce problème? Merci et bonne fin de semaine.

Répondre

5

Rappelez-vous que le nombre à virgule flottante ne peut pas représenter exactement les nombres décimaux. 2.3 * 100 donne en réalité 229.99999999999997. Ainsi, modf renvoie 229 et 0,9999999999999716.

Toutefois, le format de cout affichera uniquement des nombres à virgule flottante à 6 décimales par défaut. Ainsi, le ,9999999999999716 est représenté comme 1.


Vous pouvez utiliser (à peu près) la limite d'erreur supérieure qu'une valeur représente en virgule flottante pour éviter la 2.3 erreur:

#include <cmath> 
#include <limits> 
static double dRound(double d) { 
    double inf = copysign(std::numeric_limits<double>::infinity(), d); 
    double theNumberAfter = nextafter(d, inf); 
    double epsilon = theNumberAfter - d; 

    int factor = 100; 
    d *= factor; 
    epsilon *= factor/2; 
    d += epsilon; 

    double returnVal; 
    modf(number, &returnVal); 
    return returnVal/factor; 
} 

Résultat: http://www.ideone.com/ywmua

+0

Ainsi est-il une meilleure façon de « couper » cette queue et ne laisser que les 2 premiers chiffres après le point sans arrondi? – Matti

+0

@Matti: Voir mise à jour. – kennytm

0

est une façon ici sans arrondir:

double double_cut(double d) 
{ 
    long long x = d * 100; 
    return x/100.0; 
} 

Même si vous voulez r ounding selon 3 chiffres après la virgule, voici une solution:

double double_cut_round(double d) 
{ 
    long long x = d * 1000; 

    if (x > 0) 
     x += 5; 
    else 
     x -= 5; 

    return x/1000.0; 
}