Causa della possibile perdita di precisione dei numeri a virgola mobile
I valori decimali a virgola mobile in genere non hanno una rappresentazione binaria esatta. Questo è un effetto collaterale del modo in cui la CPU rappresenta i dati a virgola mobile. Per questo motivo, è possibile che si verifichi una perdita di precisione e alcune operazioni a virgola mobile potrebbero produrre risultati imprevisti.
Questo comportamento è il risultato di uno dei seguenti:
La rappresentazione binaria del numero decimale potrebbe non essere esatta.
Esiste una mancata corrispondenza di tipo tra i numeri usati (ad esempio, combinazione di float e double).
Per risolvere il comportamento, la maggior parte dei programmatori garantisce che il valore sia maggiore o minore di quello necessario oppure ottiene e usa una libreria BCD (Binary Coded Decimal) che manterrà la precisione.
La rappresentazione binaria dei valori a virgola mobile influisce sulla precisione e l'accuratezza dei calcoli a virgola mobile. Microsoft Visual C++ usa il formato a virgola mobile IEEE.
Esempio
// Floating-point_number_precision.c
// Compile options needed: none. Value of c is printed with a decimal
// point precision of 10 and 6 (printf rounded value by default) to
// show the difference
#include <stdio.h>
#define EPSILON 0.0001 // Define your own tolerance
#define FLOAT_EQ(x,v) (((v - EPSILON) < x) && (x <( v + EPSILON)))
int main() {
float a, b, c;
a = 1.345f;
b = 1.123f;
c = a + b;
// if (FLOAT_EQ(c, 2.468)) // Remove comment for correct result
if (c == 2.468) // Comment this line for correct result
printf_s("They are equal.\n");
else
printf_s("They are not equal! The value of c is %13.10f "
"or %f",c,c);
}
They are not equal! The value of c is 2.4679999352 or 2.468000
Commenti
Per EPSILON, è possibile usare le costanti FLT_EPSILON, definite per float come 1.192092896e-07F o DBL_EPSILON, definite per double come 2.2204460492503131e-016. Per queste costanti è necessario includere float.h. Queste costanti sono definite come il numero positivo più piccolo x, in modo che x+1,0 non sia uguale a 1,0. Poiché si tratta di un numero molto ridotto, è consigliabile usare la tolleranza definita dall'utente per i calcoli che coinvolgono numeri molto grandi.