Java: добавление /Substracting Math.ulp() vs. Math.nextAfter()
Я пытаюсь понять операции с плавающей запятой в Java более подробно. Если я правильно прочитал документацию, для любого заданного двойного x будет выполнено следующее:
x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY);
x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY);
Вопрос: Это всегда так или есть некоторые исключительные случаи, в которых результаты будут отличаться?
Ответы
Ответ 1
Эта программа:
public class Test {
public static void main(String[] args) {
double x = 1;
System.out.println(x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY));
System.out.println(x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY));
}
}
выходы:
false
true
Разница между последовательными удвоениями изменяется при каждой нормальной целочисленной мощности двух, включая 1.0. Один из тестов должен потерпеть неудачу, поскольку он предполагает постоянную разницу. Math.ulp(double) определяется как "положительное расстояние между этим значением с плавающей запятой и двойным значением, которое больше по величине", поэтому вычесть предложение ложно, когда расстояние отличается.
Ответ 2
Непосредственные случаи, которые я думаю проверить: 0, + бесконечность и -infinity и NaN:
static void check(double x) {
double a, b;
System.out.printf(
"%9s %9s %23s %5s%n",
x, a = x - Math.ulp(x), b = Math.nextAfter(x, Double.NEGATIVE_INFINITY), a == b);
System.out.printf(
"%9s %9s %23s %5s%n",
x, a = x + Math.ulp(x), b = Math.nextAfter(x, Double.POSITIVE_INFINITY), a == b);
System.out.println();
}
public static void main(String[] args) throws java.lang.Exception {
check(0);
check(Double.POSITIVE_INFINITY);
check(Double.NEGATIVE_INFINITY);
check(Double.NaN);
}
Ideone demo
Вывод:
0.0 -4.9E-324 -4.9E-324 true
0.0 4.9E-324 4.9E-324 true
Infinity NaN 1.7976931348623157E308 false
Infinity Infinity Infinity true
-Infinity -Infinity -Infinity true
-Infinity NaN -1.7976931348623157E308 false
NaN NaN NaN false
NaN NaN NaN false
То, что выражения не равны в случае NaN
, неудивительно (по определению NaN); но эти выражения также неверны для + бесконечности и -инфекции (см. последний столбец).
Этот ответ не предназначен для предоставления исчерпывающего списка проблемных значений, а скорее для того, чтобы показать, что существуют некоторые проблемные значения.