Thread: For Loops: Which Method Is Better?

  1. #1
    Registered User
    Join Date
    Jun 2012
    Posts
    1

    For Loops: Which Method Is Better?

    Hello! Writing some code recently I came up with two different ways of doing for loops/statements.

    Method 1:
    Code:
    for (int iii = 0; iii <  5; iii++)
    {
         SomeStatement;
         SomeOtherStatement;
         AnotherStatement;
    }
    Method 2:
    Code:
    for (int iii = 0; iii <  5; iii++)
         SomeStatement;
    
    for (int iii = 0; iii <  5; iii++)
         SomeOtherStatement;
    
    for (int iii = 0; iii <  5; iii++)
         AnotherStatement;
    As far as I can tell both methods are equivalent (please correct me if I'm wrong)

    Assuming both do the exact same thing, which would generally be preferred? Thanks!

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Vekta
    As far as I can tell both methods are equivalent (please correct me if I'm wrong)
    Ah, but they are not. It is the difference between:
    Code:
    ABC
    ABC
    ABC
    ABC
    ABC
    and
    Code:
    AAAAA
    BBBBB
    CCCCC
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User R41D3N's Avatar
    Join Date
    Mar 2012
    Location
    ...Beyond Infinity, Behind a KeyBoard...
    Posts
    29
    Quote Originally Posted by Vekta View Post
    Assuming both do the exact same thing, which would generally be preferred?
    It is as laserlight pointed out. The 2 dont really work in the same way.

    Method 1:
    Code:
        for(int iii = 0; iii < 5; ++iii)
        {
            cout<<"A";
            cout<<"B";
            cout<<"C";
        }

    Method 2:
    Code:
        for(int iii = 0; iii < 5; ++iii)
            cout<<"A";
    
    
        for(int iii = 0; iii < 5; ++iii)
            cout<<"B";
    
    
        for(int iii = 0; iii < 5; ++iii)
            cout<<"C";

    But lets say they do indeed do the same thing(not the above example, but your statements), then the obvious choice would be method 1 ... since it iterates just 5 times, whereas your 2nd method would iterate 15 times to achieve the same thing?
    Last edited by R41D3N; 06-18-2012 at 05:02 AM.
    -- reserved for when I come up with 1 --

  4. #4
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Method 1 is better, because you change the index fewer times, and because the loop body is bigger, which means the cpu can do more things before each branch. (Branches can slow down other instructions, unless the next instruction does not depend on the branch, or it can guess correctly if the branch is taken.) It only matters if the 3 operations are very simple however.

    Mind, this would qualify as a micro-optimisation, and not worth bothering with unless you've determined that particular command sequence to be a performance critical.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  5. #5
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by King Mir View Post
    ...which means the cpu can do more things before each branch. (Branches can slow down other instructions, unless the next instruction does not depend on the branch, or it can guess correctly if the branch is taken.)...
    This would usually be optimized by the compiler by unrolling the loop, though, and on today's OOO CPUs, the cpu would probably just continue to stuff down more and more instructions down the pipeline from subsequent iterations of the loop, limiting the performance hit.
    Also, on today's hardware, branches typically only slow down the cpu if they are mispredicted.
    Nevertheless, I agree that it is a micro-optimization.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  6. #6
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    What ?
    How can it be micro/premature optimization to write similar iterations within the same loop?
    It is as natural as ..say.. annotating while reading, not afterwards !

    Or did you two mean something else ?

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I think they are talking about manual loop unrolling. Other than that, it is nonsense to say that method 1 is better than method 2 because they don't do the same thing.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I remember getting in an argument with Mario F. about for loops once and it was nothing like this. I think though that the conclusion will be the same. The method of writing a for loop that is better is the one that works. For loops are so simple that if you can save time by doing an extra something in the initializing part of the loop, and use ++i instead of i++, it won't hurt.

  9. #9
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by Elysia View Post
    This would usually be optimized by the compiler by unrolling the loop, though, and on today's OOO CPUs, the cpu would probably just continue to stuff down more and more instructions down the pipeline from subsequent iterations of the loop, limiting the performance hit.
    Also, on today's hardware, branches typically only slow down the cpu if they are mispredicted.
    Nevertheless, I agree that it is a micro-optimization.
    Unrolling the loop wouldn't do much good if there's a data dependency with each iteration of the loop. So using 1 loop instead of 3 gives the compiler and CPU more opportunity for such optimisations.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  10. #10
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Here's an example of what I'm talking about:
    This code:
    Code:
    int foo(int array1[], int array2[],int array3[]){ 
      int product=1;
      for (int i = 0; i <  SIZE; i++)
         product *= array1[i];
    
      for (int i = 0; i <  SIZE; i++)
         array3[i] = array1[i]+array2[i];
    
      return product;
    }
    could better written like this:
    Code:
    int foo(int array1[], int array2[],int array3[]){ 
      int product=1;
      for (int i = 0; i <  SIZE; i++) {
         product *= array1[i];
         array3[i] = array1[i]+array2[i];
      }
      return product;
    }
    The second will preform better, unless the compiler can itself realize that the two are functionally equivalent. I don't think most can.
    Last edited by King Mir; 06-18-2012 at 10:23 PM. Reason: made it so it could loop unroll easily.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by King Mir
    The second will preform better, unless the compiler can itself realize that the two are functionally equivalent. I don't think most can.
    Because of possible aliasing, the two are not necessarily functionally equivalent, e.g.,
    Code:
    #include <iostream>
    
    int foo1(int array1[], int array2[],int array3[], int size){
      int product=1;
      for (int i = 0; i <  size; i++)
         product *= array1[i];
    
      for (int i = 0; i <  size; i++)
         array3[i] = array1[i]+array2[i];
    
      return product;
    }
    
    int foo2(int array1[], int array2[],int array3[], int size){
      int product=1;
      for (int i = 0; i <  size; i++) {
         product *= array1[i];
         array3[i] = array1[i]+array2[i];
      }
      return product;
    }
    
    void print(int numbers[], int size)
    {
        for (int i = 0; i < size; ++i)
        {
            std::cout << numbers[i] << " ";
        }
        std::cout << std::endl;
    }
    
    int main()
    {
        {
            int x[] = {1, 2, 3, 4, 5};
            int y[] = {5, 6, 7, 8};
            int result = foo1(x, y, x + 1, 4);
            std::cout << "result = " << result << std::endl;
            print(x, 5);
            print(y, 4);
        }
    
        {
            int x[] = {1, 2, 3, 4, 5};
            int y[] = {5, 6, 7, 8};
            int result = foo2(x, y, x + 1, 4);
            std::cout << "result = " << result << std::endl;
            print(x, 5);
            print(y, 4);
        }
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Apr 2006
    Posts
    2,149
    Quote Originally Posted by laserlight View Post
    Because of possible aliasing, the two are not necessarily functionally equivalent, e.g.,
    That's right, but in a given context that the programmer is aware of, they could be. So the compiler can't do the optimisation, because of the example you provide, and the CPU can't do the necessary code reshuffling, because it can't see far enough ahead to see the see the second loop.
    Last edited by King Mir; 06-18-2012 at 10:33 PM.
    It is too clear and so it is hard to see.
    A dunce once searched for fire with a lighted lantern.
    Had he known what fire was,
    He could have cooked his rice much sooner.

  13. #13
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by King Mir View Post
    Unrolling the loop wouldn't do much good if there's a data dependency with each iteration of the loop. So using 1 loop instead of 3 gives the compiler and CPU more opportunity for such optimisations.
    Depends on how the loop looks like, and the type of hardware.
    A modern OOO CPU will likely just continue to loop while stuffing down ops through the pipeline, so it essentially "unrolls the loop" itself.
    If there are too many data dependencies or too many loops (as in your example), then you'll have problems, though.
    I'm just speaking from a theoretical perspective, though. I can't say from a practical one, as I am not well versed in compiler technologies.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  14. #14
    Registered User sirama's Avatar
    Join Date
    Jun 2012
    Location
    Bangalore
    Posts
    7
    Go with method1 as it gives more performance compared with method 2. It depends on the content of the loop body. If three statements are dependent on each other go with method 1. If the need is kind of statement should be executed n times before we execute next statement we go with method two. So we can't say Method1 = Method2 until the thread starter says what each statement is...

  15. #15
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Screw performance. Do the thing that makes the code readable. You optimize only when the program isn't fast enough and profiling has shown you where the slow parts are.

    In King Mir's example, you have one function doing two very different things (getting the product of an array and getting elementwise sums of two arrays), so using two loops, and two separate functions in fact, is better. And while you're at it, get rid of those loops entirely and use algorithms.

    Code:
    int product(int array[], int size) {
      return std::accumulate(array, array+size, 1, std::multiplies<int>());
    }
    
    void sum_elements(int input1[], int input2[], int output[], int size) {
      std::transform(input1, input1+size, input2, output, std::plus<int>());
    }
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. converting for loops to while loops
    By nabhatt in forum C Programming
    Replies: 3
    Last Post: 02-16-2012, 09:45 PM
  2. Replies: 3
    Last Post: 06-01-2011, 04:19 PM
  3. loops, menu loops
    By gloworm in forum C Programming
    Replies: 17
    Last Post: 04-12-2010, 07:59 PM
  4. difference between this->method() and method()
    By nacho4d in forum C++ Programming
    Replies: 7
    Last Post: 11-21-2009, 04:11 PM
  5. Encrypt method (from decrypt method)
    By mmmmmm in forum C# Programming
    Replies: 3
    Last Post: 09-19-2009, 10:35 AM