2010-09-07 8 views
17

Tengo double valor d y me gustaría una forma de empujarlo ligeramente más grande (o más pequeño) para obtener un nuevo valor que sea lo más parecido posible al original pero estrictamente mayor que (o menor que) el original .¿Cómo alterar un flotante por su incremento más pequeño en Java?

No tiene que estar cerca del último bit; es más importante que cualquier cambio que realice garantice la producción de un valor diferente y no redondeado al original.

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

La razón que necesito esto, es que estoy mapeo de Double a (algo), y puede tener múltiples elementos con el 'valor' doble parada, pero todos ellos necesitan para ir individualmente en el mapa.

Mi código actual (que hace el trabajo) es el siguiente:

 

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

¿Por qué usa un tipo doble para su necesidad? Un "ID de modificación" largo sería mucho más fácil de implementar. –

+3

Esto es bastante hacky. ¿Por qué no usar un mapa de listas? –

+2

Lo que dijo @Joeri. Si necesita valores múltiples para una clave en un mapa, simplemente almacene una lista de valores para cada clave. –

Respuesta

20

Uso Double.doubleToRawLongBits y Double.longBitsToDouble:

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

La forma IEEE-754 trabajos, que le dará exactamente la próxima viable doble, es decir, la cantidad más pequeña mayor que el valor existente.

(el tiempo que va a golpear NaN y probablemente quedarse allí, pero debería funcionar para valores razonables.)

+1

¿Eso va a ser confiable en ambos endian-nesses? –

+0

Eso es exactamente lo que estaba buscando, gracias. – barryred

+0

@Jon Skeet - ¿Por qué es esto ab respuesta de etter que utilizando Double.MIN_VALUE? –

-2

d += Double.MIN_VALUE

(o -= si quiere llevar)

+5

Dado cuán pequeño es 'MIN_VALUE', esto a menudo dará como resultado que' d' no cambie. – AakashM

+4

no es correcto. si el número es grande, después de la adición y normalización 'Double.MIN_VALUE' se evaporará y el número no cambiará – Andrey

-4

Use Double.MIN_VALUE.

el Javadoc para ello:

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

¿Y qué sucede cuando lo agrega a un valor razonablemente grande? –

+0

Podría desbordarse, o podría no hacer ninguna diferencia, pero es una respuesta legítima a su pregunta, ya que es el valor más pequeño posible para un doble que es positivo. –

+3

@Richard: No hace ninguna diferencia en absoluto * no es * una respuesta legítima a la pregunta: "No tiene que ser muy cercano al último bit; es más importante que cualquier cambio que haga garantice la producción un valor diferente y no redondeado al original ". Tienes que crear un valor diferente. Agregar 'Double.MIN_VALUE' no siempre hará eso. –

3

¿Usted ha considerado el uso de una estructura de datos que permitiría múltiples valores almacenados bajo la misma clave (por ejemplo, un binario árbol) en lugar de intentar hackear el valor clave?

29

En Java 1.6 y posterior, el método Math.nextAfter(double, double) es la forma más limpia de obtener el siguiente valor de double después de un valor dado de double.

El segundo parámetro es la dirección que desee. Alternativamente, puede usar Math.nextUp(double) (Java 1.6 y posterior) para obtener el siguiente número más grande y desde Java 1.8 también puede usar Math.nextDown(double) para obtener el siguiente número más pequeño. Estos dos métodos son equivalentes a usar nextAfter con infinito positivo o negativo como dirección doble.

Específicamente, Math.nextAfter(score, Double.MAX_VALUE) le dará la respuesta en este caso.

+0

Podría ser útil tener en cuenta que el segundo parámetro es la dirección para moverse. –

+0

Bueno, no lo sabía. –

+0

@Ax. Me gustaría pensar que no es necesario hacer eso. Todo lo que necesitas saber está en los javadocs. –

Cuestiones relacionadas