2016-12-24 35 views
1

我想用BigDecimal.pow(int i)具有很大的基數和指數,但是我得到一個ArithmeticException: Underflow錯誤。BigDecimal可能的解決方案下溢錯誤

就乾脆把它的代碼是:

BigDecimal base = BigDecimal.valueOf(2147483645.4141948); 
BigDecimal product = base.pow(987654321); 

System.out.println("product = " + product.toPlainString()); 

是的,這是一個項目歐拉問題。不過,我知道我的號碼是正確的。這不是一個數學問題,它純粹是我不明白爲什麼BigDecimal.pow(int i)給我一個ArithmeticException: Underflow

我知道BigDecimalscale is a 32-bit int,但有沒有什麼辦法可以繞過這個並計算出如此大的值?如果有幫助,我打算在地板上鋪設產品,並將其修改爲100000000,因爲我只需要最後8位數字。如果還有其他的方法可以用數學方法來完成,我想要一個提示。

堆棧跟蹤:

Exception in thread "main" java.lang.ArithmeticException: Underflow 
    at java.math.BigDecimal.checkScale(BigDecimal.java:3841) 
    at java.math.BigDecimal.pow(BigDecimal.java:2013) 
    at test.main(test.java:10) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) 

Process finished with exit code 1 

感謝。

+3

' BigDecimal.valueOf(2147483645.4141948)' - 不!切勿從浮點文字構造BigDecimal;只要這樣做,你就已經招致了舍入誤差。從字符串文字構造它:'new BigDecimal(「2147483645.4141948」)'。 – user2357112

+0

@ user2357112'BigDecimal.valueOf()'把'long l'作爲它的參數,而不是字符串。 – kkmonlee

+0

哎呦,修正了。你需要構造函數,而不是valueOf。 – user2357112

回答

1

答案一個十進制數字,小數位以「11234048」(最後8位小數)結尾的小數位數爲6913580247。你有你的基地7個小數,和987654321 * 7等於6913580247.

我的問題是這樣的數字不能在BigDecimal表示,因爲它需要的6913580247規模,其溢出,BigDecimal用於其規模整數。我不知道你想用你的號碼代替哪種格式。以下代碼將結果打印爲

Result is 1.1234048e-6913580240 

也就是說,就像科學記數法一樣,只有指數超出了科學記數法的正常範圍。對於模億我使用:

public static final BigDecimal moduloBase = new BigDecimal(10).pow(8); // 8 digits 

現在我做:

long noOfDecimals = 987654321L * 7L; 

    BigDecimal bd = new BigDecimal("54141948"); // last 8 digits of base 
    bd = bd.pow(379721); 
    bd = bd.remainder(moduloBase); 
    bd = bd.pow(2601); 
    bd = bd.remainder(moduloBase); 

    double result = bd.doubleValue()/10_000_000.0; // print with 7 decimals 
    System.out.println("Result is " + result + "e" + (-(noOfDecimals - 7))); 

我使用從安東多夫任科的答案的伎倆,事實上,987654321是2601 * 379721.計算需要一些4秒,在我的電腦上,這可能會有很大的不同。

期待您的後續問題。

編輯:計算的中心部分可以用簡單的代碼使用BigInteger代替BigDecimal更快的完成都和:(它打印11234048,因爲我們現在知道它應該)

BigInteger bi = new BigInteger("54141948"); 
    bi = bi.modPow(new BigInteger("987654321"), new BigInteger("100000000")); 
    System.out.println("As BigInteger: " + bi); 

1

計算可以在幾個部分被打破,例如:

BigDecimal base = BigDecimal.valueOf(2147483645.4141948); 
base = base.setScale(20, BigDecimal.ROUND_FLOOR); 
// 109739369 = 6455257 * 17 
base = base.pow(17).setScale(20, BigDecimal.ROUND_FLOOR); 
base = base.pow(6455257); 

ArithmeticException被拋出,因爲scaleValue * powValue是外[Integer.MIN_VALUE; Integer.MAX_VALUE]段。請注意,規模,重置應用pow需要後,因爲BigDecimal規模重新計算每次pow被調用,等於oldScaleValue * powValue

而且,我認爲,這讓POW值會花很多時間