Which of these pieces of code is faster in Java?

前端 未结 16 1939
囚心锁ツ
囚心锁ツ 2020-11-30 04:25

a) for(int i = 100000; i > 0; i--) {}

b) for(int i = 1; i < 100001; i++) {}

The answer is t

相关标签:
16条回答
  • 2020-11-30 05:08

    When you get down to the lowest level (machine code but I'll use assembly since it maps one-to-one mostly), the difference between an empty loop decrementing to 0 and one incrementing to 50 (for example) is often along the lines of:

          ld  a,50                ld  a,0
    loop: dec a             loop: inc a
          jnz loop                cmp a,50
                                  jnz loop
    

    That's because the zero flag in most sane CPUs is set by the decrement instruction when you reach zero. The same can't usually be said for the increment instruction when it reaches 50 (since there's nothing special about that value, unlike zero). So you need to compare the register with 50 to set the zero flag.


    However, asking which of the two loops:

    for(int i = 100000; i > 0; i--) {}
    for(int i = 1; i < 100001; i++) {}
    

    is faster (in pretty much any environment, Java or otherwise) is useless since neither of them does anything useful. The fastest version of both those loops no loop at all. I challenge anyone to come up with a faster version than that :-)

    They'll only become useful when you start doing some useful work inside the braces and, at that point, the work will dictate which order you should use.

    For example if you need to count from 1 to 100,000, you should use the second loop. That's because the advantage of counting down (if any) is likely to be swamped by the fact that you have to evaluate 100000-i inside the loop every time you need to use it. In assembly terms, that would be the difference between:

         ld  b,100000             dsw a
         sub b,a
         dsw b
    

    (dsw is, of course, the infamous do something with assembler mnemonic).

    Since you'll only be taking the hit for an incrementing loop once per iteration, and you'll be taking the hit for the subtraction at least once per iteration (assuming you'll be using i, otherwise there's little need for the loop at all), you should just go with the more natural version.

    If you need to count up, count up. If you need to count down, count down.

    0 讨论(0)
  • 2020-11-30 05:12

    On many compilers, the machine instructions emitted for a loop going backwards, are more efficient, because testing for zero (and therefore zero'ing a register) is faster than a load immediate of a constant value.

    On the other hand, a good optimising compiler should be able to inspect the loop inner and determine that going backwards won't cause any side effects...

    BTW, that is a terrible interview question in my opinion. Unless you are talking about a loop which runs 10 millions of times AND you have ascertained that the slight gain is not outweighed by many instances of recreating the forward loop value (n - i), any performance gain will be minimal.

    As always, don't micro-optimise without performance benchmarking and at the expense of harder to understand code.

    0 讨论(0)
  • 2020-11-30 05:12

    These kinds of questions are largely an irrelevant distraction that some people get obsessed with it. Call it the Cult of Micro-optimization or whatever you like but is it faster to loop up or down? Seriously? You use whichever is appropriate for what you're doing. You don't write your code around saving two clock cycles or whatever it is.

    Let the compiler do what it's for and make you intent clear (both to the compiler and the reader). Another common Java pessimization is:

    public final static String BLAH = new StringBuilder().append("This is ").append(3).append(' text").toString();
    

    because excessive concatenation does result in memory fragmentation but for a constant the compiler can (and will) optimize this:

    public final static String BLAH = "This is a " + 3 + " test";
    

    where it won't optimize the first and the second is easier to read.

    And how about (a>b)?a:b vs Math.max(a,b)? I know I'd rather read the second so I don't really care that the first doesn't incur a function call overhead.

    There are a couple of useful things in this list like knowing that a finally block isn't called on System.exit() is potentially useful. Knowing that dividing a float by 0.0 doesn't throw an exception is useful.

    But don't bother second-guessing the compiler unless it really matters (and I bet you that 99.99% of the time it doesn't).

    0 讨论(0)
  • 2020-11-30 05:12

    This is about the dumbest question I have ever seen. The loop body is empty. If the compiler is any good it will just emit no code at all. It doesn't do anything, can't throw an exception and doesn't modify anything outside of its scope.

    Assuming your compiler isn't that smart, or that you actually didn't have an empty loop body: The "backwards loop counter" argument makes sense for some assembly languages (it may make sense to the java byte code too, I don't know it specifically). However, the compiler will very often have the ability to transform your loop to use decrementing counters. Unless you have loop body in which the value of i is explicitly used, the compiler can do this transformation. So again you often see no difference.

    0 讨论(0)
提交回复
热议问题