Dlaczego liczby zmiennoprzecinkowe mogą tracić dokładność
Wartości dziesiętne zmiennoprzecinkowe zazwyczaj nie mają dokładnej reprezentacji binarnej. Jest to efekt uboczny tego, jak procesor reprezentuje dane zmiennoprzecinkowe. Z tego powodu może wystąpić utrata precyzji, a niektóre operacje zmiennoprzecinkowe mogą powodować nieoczekiwane wyniki.
To zachowanie jest wynikiem jednego z następujących:
Reprezentacja binarna liczby dziesiętnej może nie być dokładna.
Istnieje niezgodność typów między użytymi liczbami (na przykład mieszanie zmiennoprzecinkowych i podwójnych).
Aby rozwiązać ten problem, większość programistów zapewnia, że wartość jest większa lub mniejsza niż to, co jest potrzebne, albo pobierają i używają biblioteki binarnej kodowanej liczby dziesiętnej (BCD), która zachowa precyzję.
Binarna reprezentacja wartości zmiennoprzecinkowych wpływa na precyzję i dokładność obliczeń zmiennoprzecinkowych. Program Microsoft Visual C++ używa formatu zmiennoprzecinkowego IEEE.
Przykład
// 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
Komentarze
W przypadku pliku EPSILON można użyć stałych FLT_EPSILON, który jest zdefiniowany dla zmiennoprzecinkowych jako 1.192092896e-07F lub DBL_EPSILON, który jest zdefiniowany dla wartości podwójnej jako 2.2204460492503131e-016. Należy uwzględnić zmiennoprzecinkowe.h dla tych stałych. Te stałe są definiowane jako najmniejsza liczba dodatnia x, tak aby x+1.0 nie był równy 1.0. Ponieważ jest to bardzo mała liczba, należy stosować tolerancję zdefiniowaną przez użytkownika dla obliczeń obejmujących bardzo dużą liczbę.