«Проблема», которую вы наблюдаете, связана с самой природой арифметики с плавающей запятой.
В FP точность зависит от масштаба; вокруг значения 1.0
точность не достаточна для того, чтобы различать 1.0
и 1.0+min_representable
, где min_representable
- наименьшее возможное значение, большее нуля (даже если мы рассматриваем только наименьшее нормированное число, std::numeric_limits
... наименьшая денормальность на несколько порядков меньше).
Например, с 64-битными числами с плавающей запятой с двойной точностью по шкале x=10000000000000000
(1016) невозможно отличить между x
и x+1
.
Тот факт, что разрешение изменяется со шкалой, является самой причиной имени «с плавающей запятой», поскольку десятичная точка «плавает». Вместо этого фиксированное точечное представление будет иметь фиксированное разрешение (например, с 16 двоичными цифрами ниже единиц, которые имеют точность 1/65536 ~ 0,00001).
Например, в 32-битном формате с плавающей запятой IEEE754 один бит для знака, 8 бит для экспоненты и 31 бит для мантиссы:
Наименьшее значение eps
такое что 1.0f + eps != 1.0f
доступен как предопределенная константа как FLT_EPSILON
или std::numeric_limits
. См. Также машина epsilon в Википедии , в которой обсуждается, как эпсилон относится к ошибкам округления.
I.e. epsilon - это наименьшее значение, которое делает то, что вы ожидаете здесь, делая разницу при добавлении к 1.0.
Более общая версия этого (для чисел, отличных от 1.0) называется 1 единицей на последнем месте ( мантиссы). См. Статью ULP в Википедии
.