tags:

views:

180

answers:

10

I can't decide how I should loop over ranges. This way:

for (int i = 0; i < max_i; i++) {
    for (int j = 0; j < max_j; j++) {
        // first way - two loops
    }
}

Or this way:

for (int k = 0; k < max_i*max_j; k++) {
    // second way - one loop
}

Thanks, Boda Cydo.

+2  A: 

Depends on what you do inside the loop. Do you need the indices i and j? Then I would prefer the first solution.

FredOverflow
A: 

Well it depends. If you want seperate indexes then you can use first one. if you want just a single index then the second one.

Complexity of both loops is same.

Praveen S
+2  A: 

If you decided to go with the first way, then everything is good because you have the values of both i and j. In the second way, you have to get the value of i and j manually:

for (int k = 0; k < max_i*max_j; k++) {
    i = k / max_j;
    j = k % max_j;
    ....
}

So, the first way is definitely better in your case.

AraK
+7  A: 

It depends on what you will be doing with the indices. If you're using two values separately (for example you're iterating over all permutations of the values in the two loops) then the two loop solution is more clear. The one-loop strategy is better if you don't care about the individual values but just their product instead.

Either way, choose the strategy which expresses your intent more clearly. The performance implications are trivial in comparison to the importance of the simplicity of maintaining the code.

maerics
A: 

If you use a 2D array the first one ist much more readable. In former days it was somehow common to emulate 2d arrays with a 1D, but also in this case the first is more readable.

InsertNickHere
+2  A: 

Obviously, if you have the choice, you don't need the precise value of i and j during your loop.

So the second option is better, more readable (less indentations). A little optimisation you could do, ( so as not to do the multiplication on each loop iteration):

int iKMax = max_i*max_j;
for (int k = 0; k < iKMax ; ++k)  
{
    // second way - one loop
}

And always use the prefix operator in loops (++k) cause whatever the object iterated over, it saves up one copying of this object. (cf. C++ Coding Standards: 101 Rules, Guidelines, And Best Practices by Herb Sutter and, Andrei Alexandrescu )

Stephane Rolland
+1 for **little optimization** .
Praveen S
I don't think the optimization applies to built-in types. So ++k is as effective as k++ in this particular example. Please correct me if I am wrong.
bodacydo
@Bodocydo :Optimisation is removal of the multiplication operation outside the for loop.
Praveen S
@bodacydo It's not that you are wrong. But I don't have to think whether the postfix operator is as fast as the prefix operator in some cases or another (e.g. with iterators). The fact is about premature pessimization. When you are in time to improve your C++ coding please read: C++ Coding Standards: 101 Rules, Guidelines, And Best Practices by Herb Sutter and, Andrei Alexandrescu. Choose to use the prefix ++ instead of the postfix ++ in loops.
Stephane Rolland
@bodacydo it's not a huge issue after all, but you could look at this link. It explains the prefix/postfix performance issue better than me: http://www.devx.com/tips/Tip/12634
Stephane Rolland
well, don't know about x86, but on our DSP (and on any other I can think of), (up to 2 nesting) loops are implemented with zero-overhead loop mechanism, so I can do the nesting version just as efficient as the non-nesting.
ysap
A good compiler will notice that max_i and max_j do not change throughout the loop and optimize it for you anyway. A bad compiler will not produce efficient code. Write code that is *easy to read*; only worry about performance if you *know* that it's a problem (e.g. through profiling), check that your optimizations are actually making things better, and *keep both versions*.
tc.
Where did this whole bullshit about prefix/postfix performance difference come from? **If the value of the expression is not used, `i++` and `++i` are identical!** It would take a pathological/malicious compiler to generate different code for them.
R..
@R.. If it is the case for ints, it may not be the case for std::iterator and other types of iterators, where the postfix version implies one more copy. As a consequence, using ++i (whatever its type) in loops is a good habit.
Stephane Rolland
@tc That's right, but though I presented it as an optimization, it is indeed one of my rule of coding for readability. I don't include calculus in functions and loops parameter: What may seem obvious for me, may not be for anothter. So I declare variables on the stack, with a meaningfull name. Thus the int iKMax = i_max * j_max.
Stephane Rolland
@R cf Bjarne Stroustrup C++ In-Depths Series / C++ Coding Standards 101 Rules, Guidelines and Best Practices:Chap. 9: Avoid "Using postfix ++ when the prefix version is just as good"
Stephane Rolland
Ah, I see this whole "use `++i` instead of `i++`" business is a C++ thing due to operator overloading. I'm used to C and find that, when I want to use the value of the result, it's almost always `i++` and not `++i` that fits my needs, so I've thereby come to prefer `i++` all the time.
R..
@R. Me too I really prefered it. And like you I was using i++ all the time.But, personnally I almost no longer use C style arrays []... which often implies incrementing an int variable. With std::vector, std::list, std::deque, std::set, std::map, std::multimap, and now c++0x std::unordered_map and std::array... they all implement their own std::iterator and I don't want to wonder too much... so I use ++ myIterator without questionning one second.But I understand you, indeed I was thinking this way before I completely switch to STL ways of wrtining C++.
Stephane Rolland
+3  A: 

You can't use second variant when max_i or/and max_j are large enough. Note that int is a signed type. If sizeof(int) is equal to 4 bytes, then in case when max_i=32768 and max_j=65536 you loop will be executed zero times.

If there are no special requirements I'd prefer the first variant since it more readable.

Kirill V. Lyadvinsky
+1 for catching integer overflow bug.
R..
+3  A: 

First loop is better for 2 reasons at least:

  1. It could make the nested nature of the loops clear to the reader (depending on what is required)
  2. What happens if max_i * max_j overflows in the second alternative?

Also please explore if loop index variables should be 'int' or 'size_t'. size_t is guaranteed to be positive always

Chubsdad
+1 for catching overflow.
R..
A: 

When in doubt, assume that the compiler will optimize better than you.

This is definitely not true for stuff like Android 1.0, but most C/C++ compilers are reasonably good. A good compiler ought to be able to optimize simple 2D array access (e.g. summing all the values of the array) into one loop.

tc.
A: 
Khushboo