Technical reasons behind formatting when increment

2020-01-27 02:02发布

All over the web, code samples have for loops which look like this:

for(int i = 0; i < 5; i++)

while I used the following format:

for(int i = 0; i != 5; ++i)

I do this because I believe it to be more efficient, but does this really matter in most cases?

30条回答
Evening l夕情丶
2楼-- · 2020-01-27 02:52

I think in the end it boils down to personal preference.
I like the idea of

for(int i = 0; i < 5; i++)

over

for(int i = 0; i != 5; ++i)

due to there being a chance of the value of i jumping past 5 for some reason. I know most times the chances on that happening are slim, but I think in the end its good practice.

查看更多
劳资没心,怎么记你
3楼-- · 2020-01-27 02:54

If your index were not an int, but instead (say) a C++ class, then it would be possible for the second example to be more efficient.

However, as written, your belief that the second form is more efficient is simply incorrect. Any decent compiler will have excellent codegen idioms for a simple for loop, and will produce high-quality code for either example. More to the point:

  • In a for loop that's doing heavy performance-critical computation, the index arithmetic will be a nearly negligible portion of the overall load.

  • If your for loop is performance-critical and not doing heavy computation such that the index arithmetic actually matters, you should almost certainly be restructuring your code to do more work in each pass of the loop.

查看更多
再贱就再见
4楼-- · 2020-01-27 02:55

Numeric literals sprinkled in your code? For shame...

Getting back on track, Donald Knuth once said

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

So, it really boils down to which is easier to parse

So... taking into account both of the above, which of the following is easier for a programmer to parse?

for (int i = 0; i < myArray.Length; ++i)

for (int i = 0; i != myArray.Length; ++i)

Edit: I'm aware that arrays in C# implement the System.Collections.IList interface, but that's not necessarily true in other languages.

查看更多
【Aperson】
5楼-- · 2020-01-27 02:55

When I first started programming in C, I used the ++i form in for loops simply because the C compiler I was using at the time did not do much optimization and would generate slightly more efficient code in that case.

Now I use the ++i form because it reads as "increment i", whereas i++ reads as "i is incremented" and any English teacher will tell you to avoid the passive voice.

The bottom line is do whatever seems more readable to you.

查看更多
Root(大扎)
6楼-- · 2020-01-27 02:56

I agree with what's been said about readability - it's important to have code that's easy for a maintainer to read, although you'd hope that whoever that is would understand both pre- and post-increments.

That said, I thought that I'd run a simple test, and get some solid data about which of the four loops runs fastest. I'm on an average spec computer, compiling with javac 1.7.0.

My program makes a for loop, iterating 2,000,000 time over nothing (so as not to swamp the interesting data with how long it takes to do whatever is in the for loop). It use all four types proposed above, and times the results, repeating 1000 times to get an average.

The actual code is:

public class EfficiencyTest
{
public static int iterations = 1000;

public static long postIncLessThan() {
    long startTime = 0;
    long endTime = 0;
    startTime = System.nanoTime();
    for (int i=0; i < 2000000; i++) {}
    endTime = System.nanoTime();
    return endTime - startTime;
}

public static long postIncNotEqual() {
    long startTime = 0;
    long endTime = 0;
    startTime = System.nanoTime();
    for (int i=0; i != 2000000; i++) {}
    endTime = System.nanoTime();
    return endTime - startTime;
}

public static long preIncLessThan() {
    long startTime = 0;
    long endTime = 0;
    startTime = System.nanoTime();
    for (int i=0; i < 2000000; ++i) {}
    endTime = System.nanoTime();
    return endTime - startTime;
}

public static long preIncNotEqual() {
    long startTime = 0;
    long endTime = 0;
    startTime = System.nanoTime();
    for (int i=0; i != 2000000; ++i) {}
    endTime = System.nanoTime();
    return endTime - startTime;
}

public static void analyseResults(long[] data) {
    long max = 0;
    long min = Long.MAX_VALUE;
    long total = 0;
    for (int i=0; i<iterations; i++) {
        max = (max > data[i]) ? max : data[i];
        min = (data[i] > min) ? min : data[i];
        total += data[i];
    }
    long average = total/iterations;

    System.out.print("max: " + (max) + "ns, min: " + (min) + "ns");
    System.out.println("\tAverage: " + (average) + "ns");
}

public static void main(String[] args) {
    long[] postIncLessThanResults = new long [iterations];
    long[] postIncNotEqualResults = new long [iterations];
    long[] preIncLessThanResults = new long [iterations];
    long[] preIncNotEqualResults = new long [iterations];

    for (int i=0; i<iterations; i++) {
        postIncLessThanResults[i] = postIncLessThan();
        postIncNotEqualResults[i] = postIncNotEqual();
        preIncLessThanResults[i] = preIncLessThan();
        preIncNotEqualResults[i] = preIncNotEqual();
    }
    System.out.println("Post increment, less than test");
    analyseResults(postIncLessThanResults);

    System.out.println("Post increment, inequality test");
    analyseResults(postIncNotEqualResults);

    System.out.println("Pre increment, less than test");
    analyseResults(preIncLessThanResults);

    System.out.println("Pre increment, inequality test");
    analyseResults(preIncNotEqualResults);
    }
}

Sorry if I've copied that in wrong!

The results supprised me - testing i < maxValue took about 1.39ms per loop, whether using pre- or post-increments, but i != maxValue took 1.05ms. That's a that's either a 24.5% saving or a 32.5% loss of time, depending on how you look at it.

Granted, how long it takes a for loop to run probably isn't your bottleneck, but this is the kind of optimisation that it's useful to know about, for the rare occasion when you need it.

I think I'll still stick to testing for less than, though!

Edit

I've tested decrementing i as well, and found that this doesn't really have an effect on th time it takes - for (int i = 2000000; i != 0; i--) and for (int i = 0; i != 2000000; i++) both take the same length of time, as do for (int i = 2000000; i > 0; i--) and for (int i = 0; i < 2000000; i++).

查看更多
趁早两清
7楼-- · 2020-01-27 02:57

The second is less readable, I think (if only because the "standard" practice seems to be the former).

查看更多
登录 后发表回答