Я пытаюсь определить double
эпсилон машины в Java, используя определение, что это наименьшее представимое double
значение x
, такое, что 1.0 + x != 1.0
, как и в C / C ++. Согласно Википедии, этот машинный эпсилон равен 2^-52
(52 - это количество double
бит мантиссы - 1).
В моей реализации используется функция Math.ulp()
:
double eps = Math.ulp(1.0);
System.out.println("eps = " + eps);
System.out.println("eps == 2^-52? " + (eps == Math.pow(2, -52)));
и результаты такие, как я ожидал:
eps = 2.220446049250313E-16
eps == 2^-52? true
Все идет нормально. Однако, если я проверю, что данное eps
действительно является наименьшим x
таким, что 1.0 + x != 1.0
, кажется, что есть меньшее значение, также известное как предыдущее double
значение в соответствии с Math.nextAfter()
:
double epsPred = Math.nextAfter(eps, Double.NEGATIVE_INFINITY);
System.out.println("epsPred = " + epsPred);
System.out.println("epsPred < eps? " + (epsPred < eps));
System.out.println("1.0 + epsPred == 1.0? " + (1.0 + epsPred == 1.0));
Что дает:
epsPred = 2.2204460492503128E-16
epsPred < eps? true
1.0 + epsPred == 1.0? false
Как мы видим, у нас есть меньший, чем машинный эпсилон, который, добавленный к 1, дает не 1, что противоречит определению.
Так что же не так с общепринятым значением машинного эпсилон в соответствии с этим определением? Или я что-то упустил? Я подозреваю еще один эзотерический аспект математики с плавающей запятой, но не вижу, где я ошибся ...
РЕДАКТИРОВАТЬ: Благодаря комментаторам я наконец понял. Я действительно использовал неправильное определение! eps = Math.ulp(1.0)
вычисляет расстояние до наименьшего представимого двойника> 1.0
, но - и в этом суть - что eps
не наименьшее x
с 1.0 + x != 1.0
, а скорее вдвое значение: добавление 1.0 + Math.nextAfter(eps/2)
округляется в большую до 1.0 + eps
.
strictfp
? - person davmac   schedule 26.02.2015strictfp
здесь не помогло. - person Franz D.   schedule 26.02.2015