- moyen efficace pour comparer les deux valeurs flottantes.
Un double a,b; if (a == b)
simple est un moyen efficace de comparer deux valeurs flottantes. Pourtant, comme OP l'a remarqué, cela peut ne pas atteindre l'objectif global de codage. De meilleurs moyens dépendent du contexte de la comparaison, quelque chose non fourni par OP. Voir loin ci-dessous.
- Comment ajouter une valeur flottante à un autre. Exemple. Ajouter 0,1111 à 94,4345 pour obtenir la valeur exacte 94,5456
Les valeurs flottantes code source ont gamme illimitée efficace et une précision telle que 1.23456789e1234567
. La conversion de ce texte en double
est généralement limitée à l'une des deux valeurs suivantes: . Le plus proche est sélectionné, mais cela peut ne pas correspondre exactement.
Ni 0.1111, 94.4345, 94.5456
peut être representably exactement comme double
typique.
OP a des choix:
1.) Utilisez un autre type autre que double, float
. Différentes bibliothèques offrent des types à virgule flottante décimale.
2) Limiter le code aux plates-formes rares qui prennent en charge double
à une forme de base 10 telle que FLT_RADIX == 10
.
3) Écrivez votre propre code pour gérer les entrées utilisateur comme "0.1111"
dans une structure/chaîne et effectuez les opérations nécessaires.
4) Traiter l'entrée utilisateur comme les chaînes et la convertir en type entier, toujours avec les routines supportées pour lire/calculer/et écrire.
5) Accepter que les opérations à virgule flottante ne sont pas mathématiquement exactes et gèrent l'erreur d'arrondi.
double a = 0.1111;
printf("a: %.*e\n", DBL_DECIMAL_DIG -1 , a);
double b = 94.4345;
printf("b: %.*e\n", DBL_DECIMAL_DIG -1 , b);
double sum = a + b;
printf("sum: %.*e\n", DBL_DECIMAL_DIG -1 , sum);
printf("%.4f\n", sum);
Sortie
a: 1.1110000000000000e-01
b: 9.4434500000000000e+01
sum: 9.4545599999999993e+01
94.5456 // Desired textual output based on a rounded `sum` to the nearest 0.0001
Plus sur # 1
Si une exacte pour comparer n'est pas demandée, mais une sorte de « sont les deux valeurs assez proches ? ", une définition de" assez proche "est nécessaire - dont ils sont nombreux.
La section "assez proche" compare la distance en examinant le ULP des deux nombres. C'est une différence linéaire quand les valeurs sont dans la même puissance de deux et devient logarithmique autrement. Bien sûr, le changement de signe est un problème.
float
exemple:
Tenez compte de tous float
fini de l'ordre le plus négatif à la plus positive. Le code suivant, un peu portable, renvoie un entier pour chaque float
avec même commande.
uint32_t sequence_f(float x) {
union {
float f;
uint32_t u32;
} u;
assert(sizeof(float) == sizeof(uint32_t));
u.f = x;
if (u.u32 & 0x80000000) {
u.u32 ^= 0x80000000;
return 0x80000000 - u.u32;
}
return u.u3
}
Maintenant, pour déterminer si deux float
sont "suffisamment proche", simple comparer deux entiers.
static bool close_enough(float x, float y, uint32_t ULP_delta) {
uint32_t ullx = sequence_f(x);
uint32_t ully = sequence_f(y);
if (ullx > ully) return (ullx - ully) <= ULP_delta;
return (ully - ullx) <= ULP_delta;
}
Lire [cet article SO] (http://stackoverflow.com/questions/588004/is-floating-point-math-broken). –
"on ne devrait jamais comparer deux valeurs à virgule flottante directement." Si votre professeur a dit cela, prenez un nouveau professeur. Ce qu'il aurait dû dire, c'est de ne jamais vérifier deux valeurs à virgule flottante pour ** l'égalité ** directement. Il n'y a aucun problème à les comparer pour voir si l'un est supérieur ou inférieur à l'autre. – JeremyP
Ah j'ai oublié, il a dit que le contrôle de l'égalité ne devrait pas être fait. – AstroMax