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