0

Why second loop is faster than first here.

public class Test2 {
    public static void main(String s[]) {
        long start, end;
        int[] a = new int[2500000];
        int length = a.length;
        start = System.nanoTime();
        for (int i = 0; i < length; i++) {
            a[i] += i;
        }
        end = System.nanoTime();
        System.out.println(end - start + " nano  with i < a.length ");
        int[] b = new int[2500000];
        start = System.nanoTime();
        for (int i = b.length - 1; i >= 0; i--) {
            b[i] += i;
        }
        end = System.nanoTime();
        System.out.println(end - start + " nano with i > = 0");
    }
}

Output is

6776766 nano  with i < a.length 
5525033 nano with i > = 0

update - I have update the question according to the suggestion but I still see the difference in time. first loop is taking more time then second loop.

Ashish
  • 14,295
  • 21
  • 82
  • 127
  • 2
    http://stackoverflow.com/questions/504103/how-do-i-write-a-correct-micro-benchmark-in-java – Mysticial May 01 '14 at 17:57
  • 3
    partly because in first loop you do a.length for each iteration but in second loop you do not. try extracting a.length in first also to a local variable and then see. – Nazgul May 01 '14 at 17:58
  • 1
    Getting a's length isn't free... – Michael Plotke May 01 '14 at 17:58
  • Could the difference also partially be because comparisons against 0 are a hardware instruction while arbitrary comparisons are not, or does modern hardware support arbitrary comparisons? – awksp May 01 '14 at 18:02
  • 3
    This is a terrible benchmark program. Among other things, there's no warm-up phase; the use of `System.currentTimeMillis` is notoriously inaccurate for this; there may well be an order dependency between the loops. Please use a decent Java microbenchmark tool like [Caliper](https://code.google.com/p/caliper/wiki/JavaMicrobenchmarks) or [jmh](http://openjdk.java.net/projects/code-tools/jmh/). – Ted Hopp May 01 '14 at 18:02

3 Answers3

3

Most likely it's because you're fetching the value of a.length each iteration in the first case, as opposite to once in the second case.

try doing something like

int len = a.length;

and using len as the termination border for the loop.

this could potentially reduce the time of the first loop.

vlady
  • 477
  • 1
  • 7
  • 14
2

If I modified your first for loop slightly, you'll get a similar time:

    int alength = a.length;    // pre-compute a.length
    start = System.currentTimeMillis();
    for (int i = 0; i < alength; i++) {
        a[i] += i;
    }

$ java Test
8 millis with i<a.length 
6 millis with i>=0
Santa
  • 11,381
  • 8
  • 51
  • 64
  • Thank you, I have updated my code and I can still see second loop is faster than first – Ashish May 01 '14 at 18:44
  • 1
    The difference there is minute. And I suspect it might still be tied to the one `a.length` call that you do after the start of your benchmark. – Santa May 01 '14 at 18:45
  • well I have again update the code and I have same output as before. – Ashish May 01 '14 at 20:30
1

The main reason for the difference in times is -

"... Never use System.currentTimeMillis() unless you are OK with + or - 15 ms accuracy, which is typical on most OS + JVM combinations. Use System.nanoTime() instead." – Scott Carey Found Here

Update:
I believe someone mentioned in the comments section of your question that you should also warm up the kernel your testing on, before testing micro benchmarks.

Rule 1: Always include a warmup phase which runs your test kernel all the way through, enough to trigger all initializations and compilations before timing phase(s). (Fewer iterations is OK on the warmup phase. The rule of thumb is several tens of thousands of inner loop iterations.)

Community
  • 1
  • 1
Jonny Henly
  • 4,023
  • 4
  • 26
  • 43