Sdílet prostřednictvím


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.

Viz také

Optimalizace kódu