2010-09-07 14 views
17

Mam wartość double o wartości d i chciałbym ją nieco nieznacznie zwiększyć (lub zmniejszyć), aby uzyskać nową wartość, która będzie jak najbliżej oryginału, ale wciąż będzie większa niż (lub mniejsza niż) oryginalna .Jak zmienić wartość zmiennoprzecinkową o najmniejszy przyrost w Javie?

Nie musi być zbliżony do ostatniego bitu - ważniejsze jest to, że każda zmiana, którą wprowadzę, zapewni inną wartość, a nie zaokrąglenie do oryginału.

(This question has been asked and answered for C, C++)

Powodem muszę to to, że jestem od Double do mapowania (coś), a może mam kilka pozycji z podwójnym ocalić „value”, ale wszystkie one muszą iść indywidualnie do Mapa.

Mój obecny kod (który spełnia swoje zadanie) wygląda następująco:

 

private void putUniqueScoreIntoMap(TreeMap map, Double score, 
      A entry) { 

     int exponent = 15; 
     while (map.containsKey(score)) { 
      Double newScore = score; 
      while (newScore.equals(score) && exponent != 0) { 
       newScore = score + (1.0d/(10 * exponent)); 
       exponent--; 
      } 
      if (exponent == 0) { 
       throw new IllegalArgumentException("Failed to find unique new double value"); 
      } 
      score = newScore; 
     } 
     map.put(score, entry); 
    } 
 
+1

Dlaczego używasz podwójnego typu do swoich potrzeb? Długie "modifyId" byłoby znacznie łatwiejsze do wdrożenia. –

+3

To jest dość hacky. Dlaczego nie skorzystać z mapy list? –

+2

Co powiedział @Joeri. Jeśli potrzebujesz wielu wartości dla klucza na mapie, zamiast tego zapisz listę wartości dla każdego klucza. –

Odpowiedz

20

Zastosowanie Double.doubleToRawLongBits i Double.longBitsToDouble:

double d = // your existing value; 
long bits = Double.doubleToLongBits(d); 
bits++; 
d = Double.longBitsToDouble(bits); 

Sposób IEEE-754 prace, które dadzą Ci dokładnie następny opłacalne podwójne, czyli najmniejsza ilość większa niż istniejąca wartość.

(W końcu to będzie hit NaN i prawdopodobnie pozostanie tam, ale to powinno działać na rozsądnych wartości).

+1

Czy to będzie niezawodne na obu endianach? –

+0

Dokładnie tego szukałem, dziękuję – barryred

+0

@ Jon Skeet - Dlaczego to jest ab zamiast odpowiedzi Double.MIN_VALUE? –

-2

d += Double.MIN_VALUE

(lub -= jeśli chcesz zabrać)

+5

Biorąc pod uwagę, jak mała jest "MIN_VALUE", często powoduje to, że 'd' się nie zmienia. – AakashM

+4

Nieprawidłowe. jeśli liczba jest duża, to po dodaniu i normalizacji "Double.MIN_VALUE" wyparuje, a liczba się nie zmieni – Andrey

-4

Użyj Double.MIN_VALUE.

Javadoc dla niego:

A constant holding the smallest positive nonzero value of type double, 2-1074. It is equal to the hexadecimal floating-point literal 0x0.0000000000001P-1022 and also equal to Double.longBitsToDouble(0x1L).

+1

Co się stanie, gdy dodasz to do rozsądnie dużej wartości? –

+0

Może się on przepełnić, albo nie ma żadnej różnicy, ale jest to uzasadniona odpowiedź na jego pytanie, ponieważ jest to najmniejsza możliwa wartość podwójnego pozytywu. –

+3

@Richard: Nie ma żadnej różnicy, oznacza, że ​​* nie jest * uzasadnioną odpowiedzią na pytanie: "Nie musi być blisko ostatniego fragmentu - ważniejsze jest to, że każda zmiana, którą wprowadzę, zapewni produkcję inną wartość, a nie zaokrągloną do oryginału. " Musisz stworzyć inną wartość. Dodanie 'Double.MIN_VALUE' nie zawsze to spowoduje. –

3

Czy bierzesz za pomocą struktury danych, które pozwoliłyby wiele wartości przechowywane w tej samej tonacji (np binarny drzewo) zamiast próbować zhakować wartość klucza?

29

W języku Java w wersji 1.6 i nowszych metoda Math.nextAfter(double, double) jest najczystszym sposobem uzyskania następnej wartości double po podanej wartości double.

Drugi parametr to pożądany kierunek. Alternatywnie możesz użyć Math.nextUp(double) (Java 1.6 i nowsze), aby uzyskać kolejną większą liczbę, a ponieważ Java 1.8 możesz również użyć Math.nextDown(double), aby uzyskać następną mniejszą liczbę. Te dwie metody są równoważne użyciu nextAfter z nieskończonością dodatnią lub ujemną jako kierunkiem podwójnym.

W tym przypadku odpowiedź brzmi: Math.nextAfter(score, Double.MAX_VALUE).

+0

Warto zauważyć, że drugim parametrem jest kierunek do wprowadzenia. –

+0

Nice - nie wiedziałem o tym. –

+0

@Ax. Chciałbym myśleć, że nie jest to konieczne. Wszystko, co musisz wiedzieć, to javadocs. –

Powiązane problemy