Поиск…


Числа с плавающей запятой - странные

Первая ошибка, которую делает почти каждый программист, предполагает, что этот код будет работать по назначению:

float total = 0;
for(float a = 0; a != 2; a += 0.01f) {
    total += a;
}

Программист-новичок предполагает, что это суммирует каждое отдельное число в диапазоне 0, 0.01, 0.02, 0.03, ..., 1.97, 1.98, 1.99 , чтобы получить результат 199 - математически правильный ответ.

Происходят две вещи, которые делают это неверным:

  1. Программа, как написано, никогда не завершается. a никогда не становится равным 2 , и цикл никогда не заканчивается.
  2. Если мы перепишем логику цикла для проверки a < 2 вместо этого, цикл завершится, но итоговое значение окажется чем-то отличным от 199 . На совместимых с IEEE754 машинах он часто будет содержать примерно до 201 .

Причина, по которой это происходит, заключается в том, что числа с плавающей запятой представляют собой приближенные значения их назначенных значений .

Классическим примером является следующее вычисление:

double a = 0.1;
double b = 0.2;
double c = 0.3;
if(a + b == c)
    //This never prints on IEEE754-compliant machines
    std::cout << "This Computer is Magic!" << std::endl; 
else
    std::cout << "This Computer is pretty normal, all things considered." << std::endl;

Хотя то, что мы, программист видим, это три числа, написанные в base10, то, что видят компилятор (и базовое оборудование), являются двоичными числами. Поскольку 0.1 , 0.2 и 0.3 требуют идеального деления на 10 что довольно легко в системе base-10, но невозможно в системе base-2 - эти цифры должны храниться в неточных форматах, подобно тому, как число 1/3 должен храниться в неточной форме 0.333333333333333... в базе-10.

//64-bit floats have 53 digits of precision, including the whole-number-part.
double a =     0011111110111001100110011001100110011001100110011001100110011010; //imperfect representation of 0.1
double b =     0011111111001001100110011001100110011001100110011001100110011010; //imperfect representation of 0.2
double c =     0011111111010011001100110011001100110011001100110011001100110011; //imperfect representation of 0.3
double a + b = 0011111111010011001100110011001100110011001100110011001100110100; //Note that this is not quite equal to the "canonical" 0.3!


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow