2017-11-14 71 views
12

Próbuję zrozumieć operacje zmiennoprzecinkowe w Javie bardziej szczegółowo. Gdybym poprawnie czytać dokumentację, dodaje posiada dla danego double x:Java: Dodawanie/odejmowanie Math.ulp() vs. Math.nextAfter()

x - Math.ulp(x) == Math.nextAfter(x, Double.NEGATIVE_INFINITY); 
x + Math.ulp(x) == Math.nextAfter(x, Double.POSITIVE_INFINITY); 

pytanie: czy to zawsze tak czy są jakieś wyjątkowe przypadki, w których wyniki będą się różnić?

+2

Patrząc na to, co dzieje się na liczbach całkowitych dwóch, takich jak 0,25, 0,5, 1,0, 2,0 itd., Powinniśmy uzyskać ważny wgląd w zmiennoprzecinkowe. –

Odpowiedz

9

Program:

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)); 
    } 
} 

Wyjścia:

false 
true 

Różnica pomiędzy kolejnymi zmianami deblu w każdym z normalną mocą całkowitą dwóch, w tym 1,0. Jeden z testów musi zawieść, ponieważ zakłada stałą różnicę. Math.ulp(double) jest zdefiniowany, aby zwracać "dodatnią odległość między tą wartością zmiennoprzecinkową a podwójną wartością większą w wielkości", więc propozycja odejmowania jest fałszywa, gdy odległość jest inna.

4

bezpośrednim przypadkach myślałem, by sprawdzić 0, + nieskończoność i nieskończoność i 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

wyjściowa:

 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 

że wyrażenia aren” t równe w przypadku NaN nie jest zaskakujące (z definicji NaN); ale te wyrażenia również nie są prawdziwe dla + nieskończoności i -infinity (patrz ostatnia kolumna).

Ta odpowiedź nie ma na celu dostarczenia wyczerpującej listy problematycznych wartości, ale raczej pokazania, że ​​istnieją pewne problematyczne wartości.

+0

To, że nie można "zwiększyć" + Nieskończoność ma sens. Powinno jednak działać dla "normalnych" liczb. – assylias

+3

@assylias yep, ale OP pyta "czy są jakieś wyjątkowe przypadki, w których wyniki będą się różnić?" –

+0

Biorąc pod uwagę, że przyjęta odpowiedź pokazuje, że nie działa dla żadnej mocy dwóch (w szczególności dla wersji 1.0), myślę, że jest to ... nieco mylące. –