2012-02-13 4 views
6

Il seguente programma si blocca e non riesco a capire perché.BigDecimal.movePointRight() si blocca con numeri molto grandi

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

Per gli scopi attuali, il primo metodo crea semplicemente un BigDecimal molto grande. (Dettagli: trova e alla potenza di z, anche quando questo è troppo grande per essere un doppio.Sono abbastanza sicuro che questo metodo è corretto, anche se MathContexts potrebbe non essere nei posti migliori.)

I know e^123456789 è estremamente grande, ma voglio davvero usare numeri come questo. Qualsiasi risposta sarebbe molto ben accolta.

risposta

4

In effetti non si blocca, ma l'implementazione di movePointRight nella VM di Oracle può essere estremamente inefficiente. Spesso è molto più veloce moltiplicare o dividere con una potenza di 10 invece di utilizzare i metodi movePointRight o movePointLeft. Nel tuo caso, utilizzando x.multiply(BigDecimal.TEN) probabilmente funzionerà molto meglio.

+0

Grazie. Sembra convincente, e 'x.multiply (BigDecimal.TEN)' funziona bene. Ho lasciato il mio programma durante il fine settimana (per caso), e lunedì mattina non era ancora terminato, quindi 'movePointRight' deve essere non solo estremamente, ma incredibilmente inefficiente. Tutto quello che deve fare è cambiare la "scala" di BigDecimal di 1, quindi è piuttosto sconcertante. –

+0

Non ho controllato l'intera implementazione, ma ad un certo punto, movePointXYZ crea un'istanza BigInteger intermedia nell'ordine di 10 alla potenza di (numero di cifre nel BigDecimal). Crea una stringa (in realtà un carattere []) con un "1" iniziale, seguito da circa 53 milioni di caratteri "0" e lo passa al costruttore BigInteger. L'implementazione di BigInteger tenta quindi di comprimere questo numero binario codificato in blocchi da 32 bit in un array int interno e questo è il vero colpevole. – jarnbjo