Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OutOfMemoryError on BigInteger

I'm writing a polish notation calculator for BigIntegers (just *, ^ and !) and I'm getting an OutOfMemoryError on the line where I'm subtracting BigInteger.ONE to get the factorial to work, why?

package polish_calculator;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.Stack;

public class Main {
    static BigInteger factorial(BigInteger number){
        Stack <BigInteger> factorialStack = new Stack<BigInteger>();
        factorialStack.push(number);

        while (!number.equals(BigInteger.ONE)){ //load the stack
            factorialStack.push(number.subtract(BigInteger.ONE)); // here's the error
        }

        BigInteger result = BigInteger.ONE;

        while(!factorialStack.empty()){ // empty and multiply the stack
            result.multiply(factorialStack.pop());
        }

        return result;
    }


    public static void main(String[] args) throws IOException {

        BigInteger testFactorial = new BigInteger("12");
        System.out.println(factorial(testFactorial));
        Stack <String> stack = new Stack<String>();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String readExpression = br.readLine();
        while(!readExpression.equals("")){
            String [] splittedExpression = readExpression.split(" ");
            for(int i=0; i<splittedExpression.length;i++){
                if(splittedExpression[i].equals("*"))
                {
                    BigInteger operand1 = new BigInteger(stack.pop());
                    BigInteger operand2 = new BigInteger(stack.pop());
                    BigInteger result = operand1.multiply(operand2);
                    String stackString = result.toString();
                    stack.push(stackString);
                }
                if(splittedExpression[i].equals("^"))
                {
                    BigInteger operand1 = new BigInteger(stack.pop());
                    BigInteger operand2 = new BigInteger(stack.pop());
                    BigInteger result = operand1.modPow(operand2, BigInteger.ONE);
                    String stackString = result.toString();
                    stack.push(stackString);
                }

                if(splittedExpression[i].equals("!"))
                {
                    BigInteger operand1 = new BigInteger(stack.pop());
                    BigInteger result = factorial(operand1);

                    String stackString = result.toString();
                    stack.push(stackString);
                }
                else{ //it's an integer
                    stack.push(splittedExpression[i]);
               }
            } // end for splittedExpression.length
        }
    }
}

Error:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at java.math.BigInteger.subtract(BigInteger.java:1118)
        at polish_calculator.Main.factorial(Main.java:45)
        at polish_calculator.Main.main(Main.java:65)
Java Result: 1
like image 240
andandandand Avatar asked May 14 '11 16:05

andandandand


People also ask

Does BigInteger have a limit?

The BigInteger class allows you to create and manipulate integer numbers of any size. The BigInteger class stores a number as an array of unsigned, 32-bit integer "digits" with a radix, or base, of 4294967296. The class stores the digits in little-endian order, with the most-significant digit at the end of the array.

How do you prevent OutOfMemoryError?

1) An easy way to solve OutOfMemoryError in java is to increase the maximum heap size by using JVM options "-Xmx512M", this will immediately solve your OutOfMemoryError.

How do I know if my BigInteger is negative?

signum() method helps us to identify whether a BigInteger is positive or zero or negative. It returns one of the following values depending on the following conditions: returns -1 when number is negative. returns 0 when number is zero.


1 Answers

BigInteger.subtract generates a new BigInteger, which you are pushing onto the stack.

But the original number is still the same, so the condition !number.equals(BigInteger.ONE) will never be true.

So you fill the stack forever with copies of number-1 until you run out of memory

Edited (again):

Note that is also a very memory-hungry way of calculating the factorial, since you need to push N values on the stack to calculate N! Multiplying them as you go along would be better, although of course you don't need a large N before the factorial becomes very large indeed.

See http://en.wikipedia.org/wiki/Factorial for some details on calculating large factorials efficiently.

like image 158
DNA Avatar answered Sep 22 '22 13:09

DNA