5

i am trying some math-operations with java, that does test a number if its (un)even and alter it as long as it gets to 1.

I try to run my loop for 999999times, it seems to get stuck at around ~120000times. Well, it is not stopping with an Exception, it just feels like the compiler got stuck.

I'm not that good with Java, can someone explain me what is happening here?

public static void main(String[] args) {

    int n = 0;
    int highestNumber = 0;
    int highestCounter = 0;
    int counter = 0;
    for (int i = 2;i<1000000;i++) {

        if (i%10000==0) {
            System.out.println(i);
        }
        n = i;
        while (n!=1) {
            if (n%2==0) {   
                n = n/2;
            } else {    
                n=3*n+1;
            }
            counter++;
        }
        if (counter>highestCounter) {

            highestCounter = counter;
            highestNumber = i;
            System.out.println("HIGHEST "+highestNumber+" | counter = "+counter);   
        }
        counter = 0;
        n = 0;
    }
    System.out.println("final "+highestNumber);  
}
bofredo
  • 2,348
  • 6
  • 32
  • 51
  • 8
    Just trolling: `for (int i = 2;i<1000000;i++) {` will execute 999998 times... – ppeterka Sep 27 '13 at 14:09
  • 2
    Where are the variables `counter` and `highestCounter` initialized ? – zakinster Sep 27 '13 at 14:09
  • 11
    Hi. Asking people to spot errors in your code is not especially productive. You should use the debugger (or add print statements) to isolate the problem, by tracing the progress of your program, and comparing it to what you expect to happen. As soon as the two diverge, then you've found your problem. (And then if necessary, you should construct a [minimal test-case](http://sscce.org).) – Oliver Charlesworth Sep 27 '13 at 14:09
  • 3
    The _compiler_ won't be stuck as you're able to run the code – orique Sep 27 '13 at 14:10
  • 8
    Maybe you've found the first counterexample for Collatz conjecture! ;) – isnot2bad Sep 27 '13 at 14:10
  • nah, i am just trying to solve problem 14 on projecteuler :-) but thx, i will try debugging it. – bofredo Sep 27 '13 at 14:13
  • Brute force is never the right approach form Project Euler problems. – arshajii Sep 27 '13 at 14:16
  • @arshajii how do approach it more smart? – bofredo Sep 27 '13 at 14:18
  • 1
    @bofredo Try a [dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming) approach. I don't want to give you more hints because that would just ruin the fun. – arshajii Sep 27 '13 at 14:22
  • thx thats enough, i just needed some pointing in the right direction. – bofredo Sep 27 '13 at 14:23
  • @SotiriosDelimanolis yes that is my question! :-) – bofredo Sep 27 '13 at 20:45

5 Answers5

10

You've got an overflow because 3 * n + 1 became larger than Integer.MAX_VALUE. So n gets negative and the while loop will never halt.

Use long instead of int for n!

If you want to check for the overflow instead:

while (n != 1) {
    if (n % 2 == 0) {
        n = n / 2;
    } else {
        if (n > (Integer.MAX_VALUE - 1) / 3) {
            throw new RuntimeException("overflow!");
        }
        n = 3 * n + 1;
    }
    counter++;
}

Addition for Java 8

Since Java 8, the Math class provides additional static methods for 'exact' arithmetics (addition, subtraction, multiplication, division) that throw an ArithmeticException in case of an overflow. Using these methods, the code can be simplified:

while (n != 1) {
    if (n % 2 == 0) {
        n = n / 2;
    } else {
        n = Math.addExact(Math.multiplyExact(3, n), 1);
    }
    counter++;
}
isnot2bad
  • 24,105
  • 2
  • 29
  • 50
  • it stops around 120000 and that would be ~360000. is that already overflowing it? – bofredo Sep 27 '13 at 14:17
  • @bofredo just add the Exception I showed in my example and you will see it. The highest that `n` may go is 715.827.882 – Angelo Fuchs Sep 27 '13 at 14:19
  • Only, because your initial value of n is 120000 doesn't mean that it does not become larger in the while loop! If you take for example n=6, the sequence will be 6, 3, 10, 5, 16, 8, 4, 2, 1, so n becomes 16 inbetween! (n = 113383 is the smallest n that produces an int-overflow!) – isnot2bad Sep 27 '13 at 14:20
  • @Angelo i tried it and you seem to be right! Will try using a long instead of int now. thx :) – bofredo Sep 27 '13 at 14:22
  • 1
    indeed. it was just changing n from int to long. thx problem solved and hopefully lesson learned!! – bofredo Sep 27 '13 at 14:26
  • @Angelo Just testing afterwards might be dangerous, because there are int values that produce a positive overflow for n*3+1. The first example is n=1431655765. The int result is 0 here. – isnot2bad Sep 27 '13 at 14:30
  • @isnot2bad You are right, I already edited my answer to produce output when `n` goes over the limit. – Angelo Fuchs Sep 27 '13 at 14:32
4

You have an overflow problem. Change the code like this and you see it:

    while (n!=1) {
        if(n < 0) throw new IllegalStateException("n should not become < 0" + n + "-" + counter);
        if(n > ((Integer.MAX_VALUE -1) / 3)) System.out.println("n too large. " + n);
        if (n%2==0) {   
            n = n/2;
        } else {    
            n=3*n+1;
        }
        counter++;
    }

if you make n to a long it works fine.

Angelo Fuchs
  • 9,825
  • 1
  • 35
  • 72
  • Take n = 1431655765 as a start value. It will produce a non-negative overflow (n*3+1 = 0) and the while will run forever... – isnot2bad Sep 27 '13 at 14:31
  • its still over ((Integer.MAX_VALUE -1) / 3) so will produce output. But yeah, one could argue that the Exception should be thrown in the second row, not the first one. – Angelo Fuchs Sep 27 '13 at 14:33
1

Hmm, your code looks fine to me. You're solving a pretty typical problem

Is n an integer? If it's a short you might be overflowing it.

Other than that, an integer's max value is over 2 billion, so you shouldn't be hitting it. Just in case, try setting n to a long to see if that helps

Edit: Take for example, the number 77671 According to a blog I read (read: untested) the highest n for i = 77671 is 1,047,216,490

So I think n should be a long, now that I think more about it

Chris
  • 846
  • 6
  • 16
1

This correction works:

public static void main(String []args){
    long highestCounter = -1;
    long highestNumber = -1;
    for (long i = 2;i<1000000;i++) {

        if (i%1000==0) {
            System.out.println(i);
        }
        long n = i;
        long counter = 0;
        while (n!=1) {
            if (n%2==0) {   
                n = n/2;
            } else {    
                n=3*n+1;
            }
            counter++;
        }
        if (counter>highestCounter) {

            highestCounter = counter;
            highestNumber = i;
            System.out.println("HIGHEST "+highestNumber+" | counter = "+counter);   
        }
        counter = 0;
        n = 0;
    }
    System.out.println("final "+highestNumber); 
}
luiso1979
  • 868
  • 1
  • 6
  • 18
0

You simply running an infinite loop inside while block, add System.out.println(counter); after counter++ to see what's going on..