Числа с плавающей точкой имеют ограниченную точность. В зависимости от языка и архитектуры они обычно представляются с использованием 32 бит (float
) или 64 бит (double
, с «двойной точностью»). Хотя в нетипизированном языке, таком как JavaScript, все становится размытым, под всем этим все еще есть реальная машина, и эта машина должна выполнять арифметику с плавающей запятой.
Проблема в том, что результаты некоторых вычислений не могут быть представлены точно, учитывая ограниченную точность. Это объясняется некоторыми примерами на странице Википедии об арифметике с плавающей запятой .
Для людей, которым нужны все мелкие детали, обычно рекомендуется статья о Что каждый компьютерный специалист должен знать об арифметике с плавающей точкой . А если серьезно: не каждый компьютерщик должен знать все это, и я уверен, что только немногие люди в мире на самом деле прочитали все это ...
В качестве чрезмерно наводящего примера: представьте, что у вас есть 5 цифр для хранения номера. Когда у вас есть дополнение, например
10000.
+ 0.00001
--------------------
= 10000.
часть .00001
будет в основном "усечена", поскольку она не вписывается в 5 цифр.
(это не совсем то, как это работает, но следует изложить идею)
Фактическое значение для Number.EPSILON
, согласно документации , составляет приблизительно 2,22 * 10-16 и представляет собой разницу "между 1 и наименьшее число с плавающей запятой больше 1 ". (Это иногда называют ULP, Unit In The Last Place ).
Таким образом, добавление этого значения к 1.0 приведет к другому числу. Но добавление его к 2.5 приведет к , а не , в результате получится другое число, потому что разница между 2.5 и наименьшим числом с плавающей запятой, большим 2.5, будет на больше , чем у этого эпсилона. Таким образом, эпсилон усекается, как .00001
в приведенном выше примере.
Некоторые языки / библиотеки могут предлагать функцию «ulp», которая возвращает разницу между данным значением и следующим большим представимым значением. Например, в Java у вас есть
System.out.println(Math.ulp(1.0)); // Prints 2.220446049250313E-16
System.out.println(Math.ulp(2.5)); // Prints 4.440892098500626E-16
Первый, очевидно, хранится в Number.EPSILON
. Второе значение - это значение, которое должно давать другое значение при добавлении к 2,5. Итак
2.5 < 2.5 + 4.4408E-16
будет false
и
2.5 < 2.5 + 4.4409E-16
будет true