Значение выходит за границы в цикле
Вобщем есть код:
#include <iostream>
using namespace std;
int main() {
float wet = 0;
int count = 0;
while (wet < 5) {
wet = wet + 0.1;
count++;
printf("Count equal %d\nwet equal %.4f\n", count,wet);
}
}
Вопрос: Почему переменная wet выходит за пределы и становится равной 51, хотя тут нестрогое сравнение, то есть по идее она должна остановиться на 5.0 и count = 50, но при этом происходит еще одна лишняя итерация цикла
Ответы (3 шт):
Потому что float - тип с ограниченной точностью. На самом деле на предпоследней проверке у вас в wet не ровно 5.000000000000000, а что-то вроде 4.999999999999998, но поскольку вы печатаете только 4 знака после запятой, значение при печати округляется до 5.0000 и вы этого не видите.
Поэтому числа с плавающей точкой обычно проверяют не на прямое (не)равенство другому числу, а проверяют вместо этого абсолютную разность между числами на то, что она достаточно мала (или достаточно велика).
float и double значения надо сравнивать с некоторой точностью. Обычно рассматривают значения с некоторой малой границей эпсилон, с помощью которой эта точность и регулируется.
в дополнение ко всем написавшим выше касательно float, double и вообще любого числа с плавающей точкой
во-первых в системе числа хранятся в двоичной системе, а это значит, что дробь, которая в десятичной системе является конечной, например
1/10
в двоичной системе будет бесконечной, потому что 2^x = 10, где x - иррациональное число
поэтому, когда вы к конечной дроби добавляете бесконечную дробь, то результат будет представлять собой бесконечную дробь
1 + 0.1 = 1.1 - конечная дробь только в десятичной системе, в двоичной системе она уже бесконечная дробь
а это значит, что вы НИКОГДА не сможете достичь числа 5 от числа 1 путем сложения бесконечных дробей
поэтому вам не повезло и число было 4,999999999, а не 5 и на следующей итерации уже 5.09999999 или 5.100000000001
Чтобы понять проблему, можно зайти и с другой стороны:
представьте дробь 1/7 - в десятичной системе это 0,1428571429 (пусть число хранит 10 разрядов после запятой), а в семеричной системе это уже точное значение 0.1
и если вы решите сделать в десятичной системе
1 + 1/7 + 1/7 + 1/7 + 1/7 + 1/7 + 1/7 + 1/7
вы получите 2,0000000003
а в семеричной системе сделав тоже самое вы получите строго 2
