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

Exception in thread "main" java.lang.StackOverflowError at java.util.HashMap.get(Unknown Source)

Hi, Why am i getting stackoverflow exception to this program?

i know that stackoverflow usually means you have an infinite loop, but this works fine when i'm using 10000 or some other numbers lesser, wht becomes suddenly infinite with big numbers?

cypronmaya
  • 520
  • 1
  • 11
  • 24

5 Answers5

5

A StackOverflowError occurs when the call stack overflows. This happens when you have too many nested calls (because each call requires space to be reserved on the stack, and it's a finite size). I guess in your case, 20000 is too many.

You can modify the stack size of the JVM with the -Xss flag. But I'd suggest that you find a different way to compute a factorial.

Community
  • 1
  • 1
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
2

The recursive function each time that is called create a new pointer in the stack, so with an high number of calls of a recursive function you can get a StackOverflow Exception ...

Tip : replace the recursive function with a loop to resolve.

aleroot
  • 71,077
  • 30
  • 176
  • 213
1

The reason is that your factorial function is recursive and this is NOT tail recursion.

It means that every time you call the "factorial" function this call is put to the stack.

I have no idea if Java compiler can generate tail recursion calls at all, but if it can, you can simply refactor your function to a tail-call way. Otherwise just avoid recursion (a good practice in imperative languages anyway).

Community
  • 1
  • 1
Alexey Raga
  • 7,457
  • 1
  • 31
  • 40
  • 2
    The Java compiler or JVM (JIT compiler) do not (yet) optimize tail calls. Maybe in a future version. – Jesper Feb 05 '12 at 12:44
0

You can resize the Java default stack size runtime with the -Xss switch

eg: java -Xss2048k YourClass
Rico
  • 58,485
  • 12
  • 111
  • 141
Kampau Ocu
  • 1,131
  • 1
  • 7
  • 4
0

Non-recursive versions (not so much as compiled - this is Stack Overflow). There will be clearer ways to write this.

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;
           }
        }
    }
}
Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305