Exception in thread "main" java.lang.StackOverflowError - java

I have a piece of code and I could not figure out why it is giving me Exception in thread "main" java.lang.StackOverflowError.
This is the question:
Given a positive integer n, prints out the sum of the lengths of the Syracuse
sequence starting in the range of 1 to n inclusive. So, for example, the call:
lengths(3)
will return the the combined length of the sequences:
1
2 1
3 10 5 16 8 4 2 1
which is the value: 11. lengths must throw an IllegalArgumentException if
its input value is less than one.
My Code:
import java.util.HashMap;
public class Test {
HashMap<Integer,Integer> syraSumHashTable = new HashMap<Integer,Integer>();
public Test(){
}
public int lengths(int n)throws IllegalArgumentException{
int sum =0;
if(n < 1){
throw new IllegalArgumentException("Error!! Invalid Input!");
}
else{
for(int i =1; i<=n;i++){
if(syraSumHashTable.get(i)==null)
{
syraSumHashTable.put(i, printSyra(i,1));
sum += (Integer)syraSumHashTable.get(i);
}
else{
sum += (Integer)syraSumHashTable.get(i);
}
}
return sum;
}
}
private int printSyra(int num, int count){
int n = num;
if(n == 1){
return count;
}
else{
if(n%2==0){
return printSyra(n/2, ++count);
}
else{
return printSyra((n*3)+1, ++count) ;
}
}
}
}
Driver code:
public static void main(String[] args) {
// TODO Auto-generated method stub
Test s1 = new Test();
System.out.println(s1.lengths(90090249));
//System.out.println(s1.lengths(5));
}
.
I know the problem lies with the recursion. The error does not occur if the input is a small value, example: 5. But when the number is huge, like 90090249, I got the Exception in thread "main" java.lang.StackOverflowError. Thanks all for your help. :)
I almost forgot the error msg:
Exception in thread "main" java.lang.StackOverflowError
at Test.printSyra(Test.java:60)
at Test.printSyra(Test.java:65)
at Test.printSyra(Test.java:60)
at Test.printSyra(Test.java:65)
at Test.printSyra(Test.java:60)
at Test.printSyra(Test.java:60)
at Test.printSyra(Test.java:60)
at Test.printSyra(Test.java:60)

Your algorithm is fine. However int is too small for your computations, it fails for this input:
printSyra(113383, 1);
At some point integer overflows to negative value and your implementation goes crazy, recursing infinitely. Change int num to long num and you'll be fine - for some time. Later you'll need BigInteger.
Note that according to Wikipedia on Collatz conjecture (bold mine):
The longest progression for any initial starting number less than 100 million is 63,728,127, which has 949 steps. For starting numbers less than 1 billion it is 670,617,279, with 986 steps, and for numbers less than 10 billion it is 9,780,657,630, with 1132 steps.
The total number of steps is equivalent to maximum nesting level (stack depth) you can expect. So even for relatively big numbers StackOverflowError should not occur. Have a look at this implementation using BigInteger:
private static int printSyra(BigInteger num, int count) {
if (num.equals(BigInteger.ONE)) {
return count;
}
if (num.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
return printSyra(num.divide(BigInteger.valueOf(2)), count + 1);
} else {
return printSyra(num.multiply(BigInteger.valueOf(3)).add(BigInteger.ONE), count + 1);
}
}
It works even for very big values:
printSyra(new BigInteger("9780657630"), 0) //1132
printSyra(new BigInteger("104899295810901231"), 0) //2254

This is an inherent problem with recursive algorithms. Make the number of recursions large enough and you can't really avoid a stack overflow, unless the language can guarantee tail-call optimization (Java and most C-like languages don't). The only way to truly fix it is to "unroll" the recursion, rewriting the algorithm iteratively or with a helper function to simulate the state-passing of the recursive call without actually nesting calls.

One solution is to allow the JVM to take more space for stack recursion, using the java -Xss parameter. Its default is less than a megabyte, IIRC, which could limit to a couple of hundred recursions max.
A better solution is to rewrite the exercise without recursion:
private int printSyra(int num){
int count = 1;
int n = num;
while(n != 1){
if(n%2==0){
n = n/2;
++count;
}
else{
n=(n*3)+1;
++count;
}
}
return count;
}

Related

Java throwing division by zero error?

In an attempt to relearn how to write code in Java I've been going through some problems from Project Euler. The following code I've written is to solve problem 3: finding the largest prime factor of the number 600851475143.
public class ProjectEuler {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ProjectEuler t = new ProjectEuler();
System.out.println(t.findLargestPrime(600851475143L));
}
public Boolean isPrime(int x) {
Boolean answer = true;
for (int i = 2; i < x/2; i++) {
if (x%i == 0) {
answer = false;
}
}
return answer;
}
public int findLargestPrime(Long max) {
int largest = 1;
for (int i = 2 ; i < max/2; i++) {
if (max%i == 0 && isPrime(i) && i > largest) {
largest = i;
}
}
return largest;
}
}
However, when I run it the code throws an arithmetic error because I'm trying to divide by zero? The actual error message is shown here:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at projecteuler.ProjectEuler.findLargestPrime(ProjectEuler.java:37)
at projecteuler.ProjectEuler.main(ProjectEuler.java:19)
I don't know if I've made a stupid mistake somewhere or if it's a quirk of Java that I don't understand? Could anyone shed some light on this?
Thank you.
for (int i = 2 ; i < max/2; i++) will eventually overflow (because 600851475143 / 2 is bigger than Integer.MAX_VALUE) and eventually i will equal to 0 when it will happen max%i will throw that exception.
Change i to long if you want to prevent it from happeninng (you should also change all the other int's to long).
This is not an answer to the actual question, but: You do not have to check all the numbers up to max, and you do not even have to do any checks whether a divisor is prime. You just have to (repeatedly) divide the max by any divisor i you found.
long l = 600851475143L;
for (int i = 2; i <= Math.sqrt(l); i++) {
if (l % i == 0) {
System.out.println(i);
l /= i;
i--;
}
}
System.out.println("--> " + l);
This way, you know that this divisor must be prime -- if it were composite, max would already have been divided by its components. This also means that you do not have to loop all the way up to max (which, for the given value, would take a really long time), but only up to the largest prime divisor, which might be much much smaller. And once you reach sqrt(l) -- for the current value of l, not the original! -- you can stop, since there can not be any divisors higher than that, and the remaining value of l will be the final (and thus, largest) prime factor.
Thus, this reduces the complexity from about O(n²) to about O(n½).

Stack overflow error in Java recursion

I'm trying to implement a code that returns the sum of all prime numbers under 2 million. I have an isPrime(int x) method that returns true if the the number is prime. Here it is:
public static boolean isPrime(int x) {
for (int i = 2; i < x; i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
And the other method, which I'm trying to implement recursively, only works until a certain number, over that number and I get a stack overflow error. The highest I got the code to work was for 10,000.
Here it is:
public static int sumOfPrimes(int a) {
if (a < 2000000) { //this is the limit
if (isPrime(a)) {
return a + sumOfPrimes(a + 1);
} else {
return sumOfPrimes(a + 1);
}
}
return -1;
}
So why do I get a stack overflow error when the number gets bigger and how can I deal with this?
Also, how do you normally deal with writing code for such big numbers? IE: normal number operations like this but for larger numbers? I wrote this recursively because I thought it would be more efficient but it still wont work.
Your isPrime function is inefficient, it doesn't have to go to x, it's enough to go to the square root of x.
But that is not the reason why your solution doesn't work. You cannot have a recursion depth of 1 million.
I would solve this problem iteratively, using the sieve of eratosthenes and for loop over the resulting boolean array.
In general if you would still like to use recursion, you can use tail recursion.
In recursion each function call will push some data to the stack, which is limited, thus generating a stackoverflow error. In tail recursion you won't be pushing anything to the stack, thus not throwing the exception.
Basically all you need is sending the data of the previous computation as parameter instead of having it on the stack.
So:
function(int x) {
// end condition
return function(x - 1) + x;
}
with tail recursion would be
function (int max, int curr, int prev, int sum) {
if (curr > max)
return sum;
return function (max, curr + 1, curr, sum + curr)
}
Keep in mind this is just pseudo code not real java code, but is close enough to the java code.
For more info check
What is tail recursion?
Use Sieve of Eratosthenes:-
Following is the algorithm to find all the prime numbers less than or equal to a given integer n by Eratosthenes’ method:
1) Create a list of consecutive integers from 2 to n: (2, 3, 4, …, n).
2) Initially, let p equal 2, the first prime number.
3) Starting from p, count up in increments of p and mark each of these numbers greater than p itself in the list. These numbers will be 2p, 3p, 4p, etc.; note that some of them may have already been marked.
4) Find the first number greater than p in the list that is not marked. If there was no such number, stop. Otherwise, let p now equal this number (which is the next prime), and repeat from step 3.
public static void main(String[] args) {
int n = 30;
System.out.printf("Following are the prime numbers below %d\n", n);
SieveOfEratosthenes(n);
}
static void markMultiples(boolean arr[], int a, int n)
{
int i = 2, num;
while ( (num = i*a) <= n )
{
arr[ num-1 ] = true; // minus 1 because index starts from 0.
++i;
}
}
// A function to print all prime numbers smaller than n
static void SieveOfEratosthenes(int n)
{
// There are no prime numbers smaller than 2
if (n >= 2)
{
// Create an array of size n and initialize all elements as 0
boolean[] arr=new boolean[n];
for(int index=0;index<arr.length-1;index++){
arr[index]=false;
}
for (int i=1; i<n; ++i)
{
if ( arr[i] == false )
{
//(i+1) is prime, print it and mark its multiples
System.out.printf("%d ", i+1);
markMultiples(arr, i+1, n);
}
}
}
}
Output:-
Following are the prime numbers below 30
2 3 5 7 11 13 17 19 23 29

Optimizing recursive method

I have some code that needs to run with some rather large numbers, and it involves incrementing into a recursive method and is therefor very slow to the point where I can't even get to my desired answer. Could someone help me optimize it? I am a beginner though, so I can't do anything very complex/difficult.
public class Euler012{
public static void main(String[]args){
int divisors=0;
for(long x=1;divisors<=501;x++){
divisors=1;
long i=triangle(x);
for(int n=1;n<=i/2;n++){
if(i%n==0){
divisors++;
}
}
//System.out.println(divisors+"\n"+ i);
System.out.println(i+": " + divisors);
}
}
public static long triangle(long x){
long n=0;
while(x>=0){
n+=x;
x--;
triangle(x);
}
return n;
}
}
First: i don't think its an optimization problem, because its a small task, but as mentioned in the comments you do many unnecessary things.
Ok, now lets see where you can optimize things:
recursion
recursion has usually a bad performance, especially if you don't save values this would be possible in your example.
e.g.: recursive triangle-number function with saving values
private static ArrayList<Integer> trianglenumbers = new ArrayList<>();
public static int triangleNumber(int n){
if(trianglenumbers.size() <= n){
if(n == 1)
trianglenumbers.add(1);
else
trianglenumbers.add(triangleNumber(n-1) + n);
}
return trianglenumbers.get(n-1);
}
but as mentioned by #RichardKennethNiescior you can simply use the formula:
(n² + n)/2
but here we can do optimization too!
you shouldnt do /2 but rather *0.5 or even >>1(shift right)
but most compilers will do that for you, so no need to make your code unreadable
your main method
public static void main(String[]args){
int divisors = 0; //skip the = 0
for(long x=1;divisors<=501;++x){ // ++x instead of x++
divisors=0;
long i=(x*x + x) >> 1; // see above, use the one you like more
/*how many divisors*/
if(i == 1) divisors = 1;
else{ /*1 is the only number with just one natural divisor*/
divisors = 2; // the 1 and itself
for(int n = 2; n*n <= i; ++n){
if(n*n == i) ++divisors;
else if(i%n == 0) divisors += 2;
}
}
System.out.println(i+": " + divisors);
}
}
the ++x instead of x++ thing is explained here
the how many divisors part:
every number except 1 has at least 2 divisors (primes, the number itself and one)
to check how many divisors a number has, we just need to go to the root of the number
(eg. 36 -> its squareroot is 6)
36 has 9 divisors (4 pares) {1 and 36, 2 and 18, 3 and 12, 4 and 8, 6 (and 6)}
1 and 36 are skiped (for(**int n = 2**)) but counted in divisors = 2
and the pares 2, 3 and 4 increase the number of divisors by 2
and if its a square number (n*n == i) then we add up 1
You dont have to generate a new triangle number from scratch each time, if you save the value to a variable, and then add x to it on the next iteration, you dont really need to have the triangle method at all.

Fibonocci Generation by Recursion

I am trying to create a method that will generate a Fibonacci sequence based on user input and calculated to the tenth number, all through recursion. (Learning recursion right now, this is one exercise).
Here is my attempted code, which I am currently struggling to make work:
//being run with fibonacci(10, 10);
//Start being the number the sequence starts with
public static int fibonacci(int start, int times)
{
if(times > 0)
{
int result = fibonacci(start - 1, times - 1) + fibonacci(start - 2, times - 1);
sequence += result;
return result;
}
System.out.println(sequence);
return start;
}
This, however, returns a large amount (I think about 40,000 numbers taking approximately 10 seconds to run to completion). Also all the numbers appear to be negative, definitely not what my aim was.
Now, on to identifying the problem: I believe the problem is that the method is calling itself twice more every single time it is called, adding up to the large amount. However, I can't think of a way around this seeing as I am trying to do it through recursion each time and I have no choice but to call it again.
As for why it is negative, I haven't a clue. I thought I was using the Fibonacci equation correctly, but obviously I am doing something incorrectly.
Could anyone help me through this please?
(True, I could easily google some code for this as I am sure it is out there, but I want to actually learn how this is done and what I am doing wrong for future reference. Better to advance as a programmer than to get the grade from copied code and move on)
I think you are a little confused here with what the Fibonacci sequence is. The formula is F(n) = F(n-1) + F(n-2). Recursion should always end at a base case which for Fibonacci is F(0) = 0 and F(1) = 1. Your method only needs one variable which is n.
Think about it this way:
public static int fibonacci(int n) {
//Insert your base cases here to terminate early
//Then process the recursive formula
return fibonacci(n - 1) + fibonacci(n - 2);
}
I think I understand what you are trying to do. You want 10 fibonacci numbers from start. Perhaps something like this will work:
public static int[] fibonacci(int start, int times)
{
return fibonacci(start, times, 0, 1, new int[times]);
}
private static int[] fibonacci(int start, int times, int a, int b, int[] answer)
{
if( start > 0 )
return fibonacci(start-1, times, b, a+b, answer);
if( times > 0 )
{
answer[answer.length - times] = a;
return fibonacci(start, times-1, b, a+b, answer);
}
return answer;
}
public static void main(String[] args) {
int[] a = fibonacci(5, 10);
for(int i=0; i<a.length; i++)
{
System.out.println(a[i]);
}
}

Project Euler Number 3

First of all, this isn't homework... working on this outside of class to get some practice with java.
public class Problem3 {
public static void main(String[] args) {
int n = 13195;
// For every value 2 -> n
for (int i=2; i < n; i++) {
// If i is a multiple of n
if (n % i == 0) {
// For every value i -> n
for (int j=2; j < i; j++) {
if (n % j != 0) {
System.out.println(i);
break;
}
}
}
}
}
}
I keep modifying the code to try to make it do what I want.
As the problem says, you should be getting 5, 7, 13 and 29.
I get these values, plus 35, 65, 91, 145, 203, 377, 455, 1015, 1885, and 2639. I think I'm on the right track as I have all the right numbers... just have a few extras.
And in checking a few of the numbers in both being divisible by n and being prime numbers, the issue here is that the extra numbers aren't prime. Not sure what's going on though.
If anyone has any insight, please share.
This part
for (int j=2; j < i; j++) {
if (n % j != 0) {
System.out.println(i);
break;
}
doesn't check whether i is prime. Unless i is small, that will always print i at some point, because there are numbers smaller than i that don't divide n. So basically, that will print out all divisors of n (It wouldn't print the divisor 4 for n == 12, for example, but that's an exception).
Note also that the algorithm - using long instead of int to avoid overflow - even if fixed to check whether the divisor i is prime for deciding whether to print it, will take a long time to run for the actual target. You should investigate to find a better algorithm (hint: you might want to find the complete prime factorisation).
I solved this problem in Java and looking at my solution the obvious advice is start using BigInteger, look at the documentation for java.math.BigInteger
Also a lot of these problems are "Math" problems as much as they are "Computer Science" problems so research the math more, make sure you understand the math reasonably well, before coming up with your algorithm. Brute force can work some times, but often there are tricks to these problems.
Brut force can also work for checking whether factor is prime or not for this problem...
eg.
for(i=1;i<=n;i++)// n is a factor.
{
for(j=i;j>=1;j--)
{
if(i%j==0)
{
counter++;// set counter=0 befor.
}
if(counter==2) // for a prime factor the counter will always be exactly two.
{
System.out.println(i);
}
counter=0;
}
}
Don't know about Java but here is my C code if it is of any help.
# include <stdio.h>
# include <math.h>
// A function to print all prime factors of a given number n
void primeFactors(long long int n)
{
// Print the number of 2s that divide n
while (n%2 == 0)
{
printf("%d ", 2);
n = n/2;
}
int i;
// n must be odd at this point. So we can skip one element (Note i = i +2)
for ( i = 3; i <= sqrt(n); i = i+2)
{
// While i divides n, print i and divide n
while (n%i == 0)
{
printf("%d ", i);
n = n/i;
}
}
// This condition is to handle the case whien n is a prime number
// greater than 2
if (n > 2)
printf ("%ld ", n);
}
/* Driver program to test above function */
int main()
{
long long int n = 600851475143;
primeFactors(n);
return 0;
}
Its very good that you are working on such problems out of class.
Saw your code. You are writing a procedural code inside main function/thread.
Instead write functions and think step by step algorithmically first.
The simple algorithm to solve this problem can be like this:
1) Generate numbers consecutively starting from 2 which is the least prime, to 13195/2. (Any number always has its factor smaller than half of it's value)
2) Check if the generated number is prime.
3) If the number is prime then check if it is factor of 13195;
4) Return the last prime factor as it is going to be the largest prime factor of 13195;
One more advice is try writting seperate functions to avoid code complexity.
Code is like this...
public class LargestPrimeFactor {
public static long getLargestPrimeFactor(long num){
long largestprimefactor = 0;
for(long i = 2; i<=num/2;i++){
if(isPrime(i)){
if(num%i==0){
largestprimefactor = i;
System.out.println(largestprimefactor);
}
}
}
return largestprimefactor;
}
public static boolean isPrime(long num){
boolean prime=false;
int count=0;
for(long i=1;i<=num/2;i++){
if(num%i==0){
count++;
}
if(count==1){
prime = true;
}
else{
prime = false;
}
}
return prime;
}
public static void main(String[] args) {
System.out.println("Largest prime factor of 13195 is "+getLargestPrimeFactor(13195));
}
}

Categories

Resources