2012-02-05 115 views
2
import java.math.BigInteger; 
import java.util.HashMap; 

/** 
* 
* @author cypronmaya 
*/ 
public class test { 
    static HashMap<Integer, BigInteger> cache = new HashMap<Integer, BigInteger>(); 
    public static void main(String[] args) { 
    System.out.println(factorial(20000)); 
    } 

    public static BigInteger factorial(int n) { 
     BigInteger ret; 
     if (n == 0) { 
      return BigInteger.ONE; 
     } 
     if (null != (ret = cache.get(n))) { 
      return ret; 
     } 
     ret = BigInteger.valueOf(n).multiply(factorial(n - 1)); 
     cache.put(n, ret); 
     return ret; 
    } 
} 

在 java.util.HashMap.get(來源不明)異常線程 「main」 java.lang.StackOverflowError的這是什麼原因爲stackoverflow異常?

嗨, 爲什麼我收到計算器例外程序?

我知道,stackoverflow通常意味着你有一個無限循環, ,但這工作正常,當我使用10000或其他數字較小,突然無限大數字?

+0

你可以計算階乘'(10000)''然後階乘(20000)'。 ;)(這個代碼是線程敵對的,順便說一句,對於負數'n'有點奇怪。) – 2012-02-05 12:36:49

回答

4

A StackOverflowError發生在調用堆棧溢出時。當你有太多的嵌套調用時(這是因爲每個調用都需要在堆棧上保留空間,並且它的大小是有限的)。我想你的情況,20000是太多了。

您可以用-Xss標誌修改JVM的堆棧大小。但我建議你找到一種不同的方法來計算階乘。

+0

同意這一點。修改堆棧大小是你可以做的事情,但不是這種類型的問題。 @cypronmaya你應該尋找另一種編程階乘的方式。 – 2012-02-05 12:29:34

+0

我認爲使用緩存會加快進一步調用因子 – cypronmaya 2012-02-05 12:48:57

+0

@oli charlesworth你能建議一個因子計劃,它可以計算更高的數字並且還有緩存(用於使事情進一步因子調用更快) – cypronmaya 2012-02-05 12:51:28

2

遞歸函數每次調用創建堆棧中的一個新的指針,因此有大量的遞歸函數就可以得到的StackOverflow異常的通話時間...

提示:更換用循環來遞歸函數來解決。

1

原因是你的階乘函數是遞歸的,這不是tail recursion

這意味着每次調用「factorial」函數時,都會將此調用放入堆棧。

我不知道Java編譯器是否可以生成尾遞歸調用,但如果可以的話,您可以簡單地將函數重構爲尾調用方式。否則,只要避免遞歸(無論如何都是命令式語言的一個好習慣)。

+2

Java編譯器或JVM(JIT編譯器)尚未(尚未)優化尾部調用。也許在未來的版本中。 – Jesper 2012-02-05 12:44:23

0

非遞歸版本(不像編譯 - 這是堆棧溢出)。將有更清晰的方式來寫這個。

public class Test { 
    private static final Object lock = new Object(); 
    private static final List<BigInteger> cache = new ArrayList<>(
     Arrays.asList(BigInteger.ONE) 
    ); 
    public static void main(String[] args) { 
     System.out.println(factorial(20000)); 
    } 

    public static BigInteger factorial(int n) { 
     if (n < 0) { 
      throw new IllegalArgumentException(); 
     } 
     synchronized (lock) { 
      int r = cache.size(); 
      if (n < r) { 
       return cache.get(n); 
      } 
      BigInteger current = cache.get(r-1); 
      for (;;) { 
       current = BigInteger.valueOf(r).multiply(current); 
       cache.add(current); 
       if (n == r) { 
        return current; 
       } 
       ++r; 
      } 
     } 
    } 
} 
0

,您可以調整默認的Java堆棧大小運行與-Xss switch

eg: java -Xss2048k YourClass 
相關問題