Почему может уменьшиться точность чисел с плавающей запятой

Десятичные значения с плавающей запятой, как правило, не имеют точного двоичного представления. Это побочный эффект того, как данные с плавающей запятой представляются в ЦП. По этой причине может происходить некоторая потеря точности, а некоторые операции с плавающей запятой могут давать непредвиденный результат.

Причины такого поведения могут быть следующими.

  • Двоичное представление десятичного числа может быть неточным.

  • Несоответствие типов используемых чисел (например, float и double).

Для решения этой проблемы большинство программистов либо гарантируют, что значение больше или меньше необходимого, либо используют библиотеку двоично-десятичного кода (BCD), которая будет обеспечивать точность.

Двоичное представление значений с плавающей запятой влияет на точность и правильность вычислений с плавающей запятой. В Microsoft Visual C++ используется формат IEEE с плавающей запятой.

Пример

// 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

Комментарии

Для EPSILON можно использовать константу FLT_EPSILON, которая определена для float как 1,192092896e-07F, или DBL_EPSILON, которая определена для double как 2,2204460492503131e-016. Для этих констант необходимо включить файл float.h. Эти константы определены как наименьшее положительное число x, при котором x + 1,0 не равно 1,0. Так как это очень маленькое число, для вычислений с очень большими числами следует использовать пользовательскую погрешность.

См. также

Оптимизация кода