Question

Je me demandais s'il existe un moyen de surmonter un problème de précision qui semble être le résultat de la représentation interne de ma machine des nombres à virgule flottante:

Pour plus de clarté, le problème est résumé comme:

// str is "4.600";   atof( str ) is 4.5999999999999996  
double mw = atof( str )  

// The variables used in the columns calculation below are:   
//  
//                    mw = 4.5999999999999996  
//                    p = 0.2  
//                    g = 0.2  
//                    h = 1 (integer)  

int columns = (int) ( ( mw - ( h * 11 * p ) ) / ( ( h * 11 * p ) + g ) ) + 1;

Avant le coulage d'un type entier, le résultat du calcul des colonnes est de 1.9999999999999996; Si près pourtant si loin du résultat souhaité de 2.0.

Toutes les suggestions les plus bienvenues.

Était-ce utile?

La solution

Un moyen très simple et efficace de contourner un numéro de point flottant vers un entier:

int rounded = (int)(f + 0.5);

Remarque: cela ne fonctionne que si f est toujours positif. (merci j pirate aléatoire)

Autres conseils

Lorsque vous utilisez le point flottant, l'égalité stricte arithmétique est presque dénuée de sens. Vous souhaitez généralement comparer avec une gamme de valeurs acceptables.

Notez que certaines valeurs peuvent ne pas être représenté exactement comme des vlues de points flottants.

Voir Ce que chaque informaticien doit savoir sur l'arithmétique à virgule flottante et Comparaison des numéros de points flottants.

Il n'y a pas de problème d'accurratie.

Le résultat que vous avez obtenu (1.9999999999999996) différait du résultat mathématique (2) par une marge de 1E-16. C'est assez précis, compte tenu de votre entrée "4.600".

Vous avez un problème d'arrondi, bien sûr. L'arrondissement par défaut en C ++ est la troncature; Vous voulez quelque chose de similaire à la solution de Kip. Les détails dépendent de votre domaine exact, vous attendez-vous round(-x)== - round(x) ?

Si vous ne l'avez pas lu, le titre de ce papier est vraiment correct. Veuillez envisager de le lire, pour en savoir plus sur les principes fondamentaux de l'arithmétique à virgule flottante sur les ordinateurs modernes, certains pièges et explications sur les raisons pour lesquelles ils se comportent comme ils le font.

Si la précision est vraiment importante, vous devriez envisager d'utiliser des nombres de points flottants à double précision plutôt que du simple point flottant. Bien qu'à partir de votre question, il semble que vous l'êtes déjà. Cependant, vous avez toujours un problème avec la vérification des valeurs spécifiques. Vous avez besoin de code dans le sens de (en supposant que vous vérifiez votre valeur contre zéro):

if (abs(value) < epsilon)
{
   // Do Stuff
}

où "epsilon" est une valeur petite mais non nulle.

Sur les ordinateurs, les nombres de points flottants ne sont jamais exacts. Ils ne sont toujours qu'une approximation proche. (1E-16 est proche.)

Parfois, il y a des bits cachés que vous ne voyez pas. Parfois, les règles de base de l'algèbre ne s'appliquent plus: a * b! = B * a. Parfois, la comparaison d'un registre à la mémoire montre ces différences subtiles. Ou à l'aide d'un coprocesseur mathématique par rapport à une bibliothèque de points flottants d'exécution. (Je fais aussi ce waayyy longtemps.)

C99 définit: (Regardez dans Math.H)

double round(double x);
float roundf(float x);
long double roundl(long double x);

.

Ou vous pouvez rouler le vôtre:

template<class TYPE> inline int ROUND(const TYPE & x)
{ return int( (x > 0) ? (x + 0.5) : (x - 0.5) ); }

Pour l'équivalence des points flottants, essayez:

template<class TYPE> inline TYPE ABS(const TYPE & t)
{ return t>=0 ? t : - t; }

template<class TYPE> inline bool FLOAT_EQUIVALENT(
    const TYPE & x, const TYPE & y, const TYPE & epsilon )
{ return ABS(x-y) < epsilon; }

Utilisez des décimales: Decnumber ++

Vous pouvez lire ceci papier pour trouver ce que vous recherchez.

Vous pouvez obtenir la valeur absolue du résultat vu ici:

x = 0.2;  
y = 0.3;  
equal = (Math.abs(x - y) < 0.000001)  
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top