java.lang.StackOverflowError exception for large i

2019-09-12 05:31发布

问题:

Basically, I'm writing a program to do a simple division manually where I want the decimal place upto 10^6 places. The program works for inputs <3000, but when I go higher, it shows: Exception in thread "main" java.lang.StackOverflowError

Here's my code:

{
....
....
int N=100000;//nth place after decimal point
String res=obj.compute(N,103993.0,33102.0,ans); //division of 103993.0 by 33102.0
System.out.println(res);
}

public String compute (int n, double a, double b, String ans){
        int x1=(int)a/(int)b;
        double x2=a-x1*b;
        double x3=x2*10;
        int c=0;
        if (n==0||n<0)
            return ("3."+ans.substring(1));
        else if (x3>b){
            ans+=""+x1;
            c=1;
        }
        else if(x3*10>b){
            ans+=x1+"0";
            c=10;
        }
        else if(x3*100>b){
            ans+=x1+"00";
            c=100;
        }
        else if(x3*1000>b){
            ans+=x1+"000";
            c=1000;
        }
        else if(x3*10000>b){
            ans+=x1+"0000";
            c=10000;
        }
        return compute(n-String.valueOf(c).length(),x3*c,b,ans);
    }

I'm not any hard-core programmer of Java. I need help in tackling this situation. I read some SO posts about increasing the stack size, but I didn't understand the method.

回答1:

Using recursivity for this kind of computation is a good idea, but every sub-call you make, stores pointers and other info in the stack, eventually filling it. I don't know the depths of the VM, but I think that JVM's max heap or stack size depends on how much contiguous free memory can be reserved, so your problem might be solved by using the -Xssparameter, that changes the size of the stack (e.g. java -Xss8M YourClass). If this still doesn't work or you cannot get enought memory, I would try with a 64-bit JVM.

If all that doesn't workk, contrary to the usual good practice I would try to do this program without recursivity.

I hope this helps!



回答2:

The recursive call from compute() to compute is causing the stack to overflow. Alter your method to use a loop rather than recursion and it would scale much better. See the wikipedia page for different division algorithms you could use: https://en.wikipedia.org/wiki/Division_%28digital%29

Alternatively use BigDecimal like so:

public class Main {
    public static void main(String... args) {
        final int precision = 20;
        MathContext mc = new MathContext(precision, RoundingMode.HALF_UP);
        BigDecimal bd = new BigDecimal("103993.0");
        BigDecimal d = new BigDecimal("33102.0");
        BigDecimal r = bd.divide(d, mc);
        System.out.println(r.toString());
    }
}

Output:3.1415926530119026041

Set precision to get the number of decimal places you want.