2011-05-14 12 views
5

Estoy escribiendo una calculadora de notación polaca para BigIntegers (solo *,^y!) Y obtengo un OutOfMemoryError en la línea donde restar BigInteger.ONE para obtener el factorial para trabajar, ¿por qué?OutOfMemoryError en BigInteger

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 

Respuesta

11

BigInteger.subtract genera un nuevo BigInteger, que están empujando en la pila.

embargo, el número original sigue siendo la misma, por lo que el estado! Number.equals (BigInteger.ONE) nunca será cierto.

Así llenar la pila siempre con copias del número 1 hasta que se agote la memoria

Editado (de nuevo):

Tenga en cuenta que es también una manera muy mucha memoria de cálculo de la factorial, ya que necesita presionar N valores en la pila para calcular N! Multiplicarlos sobre la marcha sería mejor, aunque, por supuesto, no necesitas una N grande antes de que el factorial llegue a ser muy grande.

Consulte http://en.wikipedia.org/wiki/Factorial para obtener más información sobre el cálculo de grandes factoriales de manera eficiente.

+0

Esto. number.subtract() en realidad no modifica el número. – Doug

+0

+1 punto muy bueno. @omgzor por lo tanto debes usar 'number = number.subtract (BigInteger.ONE);' y luego 'factorialStack.push (number);' – Boro