2012-02-13 94 views
6

下面的程序凍結,我無法解決原因。BigDecimal.movePointRight()掛起非常大的數字

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

就目前而言,第一種方法只是創建一個非常大的BigDecimal。 (細節:它發現了z的威力,即使這太大也不能成爲雙倍數。我很確定這種方法是正確的,儘管MathContext可能不在最好的位置。)

我知道e^123456789是非常大的,但我真的很想使用這樣的數字。任何答案將非常感激地收到。

回答

4

事實上,它並不凍結,但在Oracle的VM中執行movePointRight可能效率極低。乘以10的冪乘法或乘除法通常要快得多,而不是使用movePointRightmovePointLeft方法。在你的情況下,使用x.multiply(BigDecimal.TEN)可能會更好。

+0

謝謝。這聽起來令人信服,並且'x.multiply(BigDecimal.TEN)'工作正常。我在週末(偶然)離開了我的程序,並且它在星期一早上還沒有完成,所以'movePointRight'不能只是極其低效而且令人難以置信。它所要做的就是將BigDecimal的「比例」改爲1,所以這非常令人費解。 – 2012-02-13 15:22:29

+0

我沒有檢查整個實現,但是在某些時候,movePointXYZ創建了一箇中間BigInteger實例,其大小爲10的次冪(BigDecimal中的位數)。它創建一個帶有前導'1'的字符串(實際上是一個char []),隨後是大約5300萬個'0'字符,並將其傳遞給BigInteger構造函數。然後BigInteger實現嘗試將這個編碼二進制編碼打包到32位塊內部的int數組中,這是實際的罪魁禍首。 – jarnbjo 2012-02-13 18:27:58