2012-02-13 25 views
6

El siguiente programa se bloquea y no sé por qué.BigDecimal.movePointRight() se bloquea con números muy grandes

import java.math.*; 

public class BigDec { 
    public static BigDecimal exp(double z) { 
     // Find e^z = e^intPart * e^fracPart. 
     return new BigDecimal(Math.E).pow((int)z, MathContext.DECIMAL128). 
      multiply(new BigDecimal(Math.exp(z-(int)z)), MathContext.DECIMAL128); 
    } 

    public static void main(String[] args) { 
     // This works OK: 
     BigDecimal x = new BigDecimal(3E200); 
     System.out.println("x=" + x); 
     System.out.println("x.movePointRight(1)=" + x.movePointRight(1)); 

     // This does not: 
     x = exp(123456789); 
     System.out.println("x=" + x); 
     System.out.println("x.movePointRight(1)=" + x.movePointRight(1)); //hangs 
    } 
} 

Para el presente propósito, el primer método solo crea un BigDecimal muy grande. (Detalles: encuentra e en el poder de z, incluso cuando es demasiado grande para ser un doble. Estoy bastante seguro de que este método es correcto, aunque los MathContexts pueden no estar en los mejores lugares.)

Lo sé e^123456789 es muy grande, pero realmente quiero usar números como este. Cualquier respuesta sería muy gratamente recibida.

Respuesta

4

De hecho, no se bloquea, pero la implementación de movePointRight en la máquina virtual de Oracle puede ser extremadamente ineficiente. A menudo es mucho más rápido multiplicar o dividir con una potencia de 10 en lugar de utilizar los métodos movePointRight o movePointLeft. En su caso, usar x.multiply(BigDecimal.TEN) probablemente funcionará mucho mejor.

+0

Gracias. Eso suena convincente, y 'x.multiply (BigDecimal.TEN)' funciona bien. Dejé mi programa el fin de semana (por accidente), y todavía no había terminado el lunes por la mañana, así que 'movePointRight' no debe ser extremadamente, sino increíblemente ineficiente. Todo lo que tiene que hacer es cambiar la "escala" de BigDecimal por 1, así que esto es bastante desconcertante. –

+0

No he comprobado toda la implementación, pero en algún momento, movePointXYZ crea una instancia intermedia de BigInteger del orden de 10 a la potencia de (número de dígitos en el BigDecimal). Crea un String (en realidad, un char []) con un '1' inicial, seguido de unos 53 millones de '0' caracteres y lo pasa al constructor BigInteger. La implementación BigInteger luego trata de empacar este número binario codificado en trozos de 32 bits en una matriz int interna y ese es el verdadero culpable. – jarnbjo

Cuestiones relacionadas