2012-02-05 139 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 
相关问题