Как избежать ошибочных крошечных чисел при работе с числами с плавающей запятой - PullRequest
0 голосов
/ 09 декабря 2011

Иногда случается, когда я использую числа с плавающей запятой в c ++ и использую числа только как кратные, скажем, 0.1, как приращение цикла for, фактическое число, которое является итераторами цикла, не совсем кратно 0,1, нонепредсказуемо другие добавленные или вычтенные крошечные числа порядка 1 ^ -17.Как я могу избежать этого?

Ответы [ 3 ]

7 голосов
/ 09 декабря 2011

Используйте целые числа для итерации и умножьте на приращение с плавающей точкой перед использованием.

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

6 голосов
/ 09 декабря 2011

Не перебирайте числа с плавающей точкой.

Проблема в том, что 0.1 не может быть точно представлено в плавающей точке. Поэтому вместо этого вы должны сделать что-то вроде:

for (int i = 0; i < N; i++)
{
    float f = i * 0.1f;

    ...
}
1 голос
/ 09 декабря 2011

Вот отличная статья о работе с поплавками.Существует дискуссия, касающаяся именно вашего примера, с шагом 0,1:

for (double r=0.0; r!=1.0; r+=0.1) printf("*");

Сколько звезд будет напечатано?Десять?Запустите его и удивитесь.Код просто продолжает печатать звезды, пока мы не сломаем его.

В чем проблема?Как мы уже знаем, двойники не бесконечно точны.Проблема, с которой мы здесь столкнулись, заключается в следующем: в двоичном представлении 0.1 не является конечным (как в базе 10).Десятичный 0,1 эквивалентен двоичному 0,0 (0011), где часть в скобках повторяется вечно.Когда 0.1 хранится в двойной переменной, он округляется до ближайшего представимого значения.Таким образом, если мы добавим его 10 раз, результат не будет точно равен единице.

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

...