Proč čísla s plovoucí desetinnou čárkou mohou ztratit přesnost
Desetinné hodnoty s plovoucí desetinnou čárkou obvykle nemají přesnou binární reprezentaci. Jedná se o vedlejší účinek toho, jak procesor představuje data s plovoucí desetinou čárkou. Z tohoto důvodu může dojít ke ztrátě přesnosti a některé operace s plovoucí desetinnou čárkou můžou vést k neočekávaným výsledkům.
Toto chování je výsledkem jednoho z následujících kroků:
Binární reprezentace desetinného čísla nemusí být přesná.
Mezi použitými čísly existuje neshoda typu (například kombinování plovoucího a dvojitého).
Pokud chcete toto chování vyřešit, většina programátorů buď zajistí, aby hodnota byla větší nebo menší, než je potřeba, nebo získá a použije knihovnu BCD (Binary Coded Decimal), která bude udržovat přesnost.
Binární reprezentace hodnot s plovoucí desetinnou čárkou ovlivňuje přesnost a přesnost výpočtů s plovoucí desetinnou čárkou. Microsoft Visual C++ používá formát IEEE s plovoucí desetinou čárkou.
Příklad
// 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
Komentáře
Pro EPSILON můžete použít konstanty FLT_EPSILON, které jsou definovány pro float jako 1,192092896e-07F nebo DBL_EPSILON, které jsou definovány pro double jako 2.2204460492503131e-016. Pro tyto konstanty musíte zahrnout float.h. Tyto konstanty jsou definovány jako nejmenší kladné číslo x, aby x +1,0 nebylo rovno 1,0. Vzhledem k tomu, že se jedná o velmi malé číslo, měli byste použít uživatelsky definovanou toleranci pro výpočty zahrnující velmi velká čísla.