-1

Functionally there is no difference between these two loops, but is there any benefit of choosing one over the other?

for (var i = 0; i < loopLimit; i++)
{

}

VS

for (var i = 0; loopLimit > i; i++)
{

}

Is there any difference of putting the larger number to the left of the < sign vs on the right?


Running very basic testing I'ev noticed that putting the larger number on the left of the < seems to always perform slightly better then on when on the left. Here is small sample of results:

loopLimit > i averaged 41,479,219 ticks while i < loopLimit averaged 41,610,158 ticks to complete the following test loops:

void MeasureLoop()
{
    const int loopLimit = Int32.MaxValue;

    var timer = new Stopwatch();    
    timer.Start();

    for (var i = 0; i < loopLimit; i++)
    {
        //
    }

    timer.Stop();
}

and

void MeasureLoop()
{
    const int loopLimit = Int32.MaxValue;

    var timer = new Stopwatch();    
    timer.Start();

    for (var i = 0; loopLimit > i; i++)
    {
        //
    }

    timer.Stop();
}
Jesse Johnson
  • 1,638
  • 15
  • 25
  • Did you test it? – LarsTech Sep 19 '19 at 18:13
  • 3
    Functionally, no. However, the first is idiomatic in C#, Java, and C/C++. Someone seeing the second might be confused as to why it was done that way and may be looking for different behavior as a result, even though there is none. – madreflection Sep 19 '19 at 18:13
  • 3
    If `i < x` is faster than `x > i`, I'd be amazed. – gunr2171 Sep 19 '19 at 18:13
  • @LarsTech I tested that they are functionally identical. I'm wondering if there is any performance or memory benefit of one style over the other. – Jesse Johnson Sep 19 '19 at 18:15
  • Let me rephrase: Did you measure it? Make loopLimit a couple million. – LarsTech Sep 19 '19 at 18:16
  • 1
    Possible duplicate of [Is there any performance difference between greater than and greater than or equal?](https://stackoverflow.com/questions/6178761/is-there-any-performance-difference-between-greater-than-and-greater-than-or-equ) – Rudresha Parameshappa Sep 19 '19 at 18:16
  • What sort of application are you working on that _depends on_ the performance of the most basic of computing operators? You _DO NOT_ need know know the performance evaluations of each type of operator. You just need to measure your overall application. – gunr2171 Sep 19 '19 at 18:16
  • @gunr2171 none. i simply came across a loop that had the `<` flipped then what I'm use to seeing which got me thinking if there was difference in anyway. – Jesse Johnson Sep 19 '19 at 18:20
  • 4
    I'm voting to close this question as off-topic because it is about understanding the human nature of how things are written. It is not about syntax or performance. – gunr2171 Sep 19 '19 at 18:22
  • 1
    @JesseJohnson - you're focusing in the wrong areas. Your customers don't care if you produce a product that takes 350ms over one that takes 340ms. Pay attention to where the slowdowns are (likely, not this loop), measure and remedy. *DO NOT* try to learn/divine how to build high performance software from others; especially if they were unlikely aiming for high perf. – Damien_The_Unbeliever Sep 19 '19 at 18:28
  • 1
    @Damien_The_Unbeliever this has nothing to do with customers and I'm well aware that this depth of understanding is not needed to finish a project. This is not a current problem of mine rather a way to have a deeper understanding. – Jesse Johnson Sep 19 '19 at 18:37
  • @gunr2171 this question is purely about performance. that's the sole reason for posting the question. – Jesse Johnson Sep 19 '19 at 18:38
  • 1
    There is absolutly no difference and the same IL (.NET assembly) code is generated with same execution speed. The difference in measuring execution time comes from other factors like other processes running same time. The mnemonic generated by the compiler to test the condition < or > on same variables takes same processor ticks. –  Sep 19 '19 at 18:52
  • There might be some tricks the runtime can pull depending on if it sees the two loops of code as being functionally the same. So depending on the order you print it in, that could impact the performance output. Outside of that wild guess, my assumption would be user error if you are seeing one going faster. – David Royce Sep 19 '19 at 18:59
  • @DavidRoyce The question is asking about using one loop over the other, not one loop _and then_ the other; the runtime won't ever see both loop styles because only one will ultimately be chosen and used in the source code. – Lance U. Matthews Sep 19 '19 at 19:13
  • @OlivierRogier Thank you! I understand that my testing method is trivial at best and there are factors outside the test that have an affect (other processes on the computer, etc.) but when running the test ~10 times the average of each loop was always less time with the larger number on the left but could be coincidence. If you say the IL produced form these two are identical then that gives me a definite answer. – Jesse Johnson Sep 19 '19 at 19:45
  • The thing is: even if the second method is slightly faster you should still be doing the first one for the sake of readability if the difference is not too great. case closed. – Steve Sep 19 '19 at 20:14

2 Answers2

4

The question is tagged with though it's not clear from the body if this is strictly a performance question or is also open to other possibly off-topic differences between the two styles such as readability, common convention, etc. Anyways, to address the performance side of things I used BenchmarkDotNet to write benchmarks comparing the two operators in the case where the non-iterator operand is a constant as well as the case where it's a variable...

using BenchmarkDotNet.Attributes;

namespace SO58016813
{
    public static class Program
    {
        public static void Main()
        {
            BenchmarkDotNet.Running.BenchmarkRunner.Run<Benchmarks>();
        }
    }

    [ClrJob()]
    [CoreJob()]
    [CategoriesColumn()]
    [GroupBenchmarksBy(BenchmarkDotNet.Configs.BenchmarkLogicalGroupRule.ByCategory)]
    public class Benchmarks
    {
        private const int LoopLimit = int.MaxValue;

        [Benchmark(Baseline = true)]
        [BenchmarkCategory("Constant operand")]
        public void IteratorLessThanConstant()
        {
            for (var i = 0; i < LoopLimit; i++)
            {
                // Do nothing...
            }
        }

        [Benchmark()]
        [BenchmarkCategory("Constant operand")]
        public void ConstantGreaterThanIterator()
        {
            for (var i = 0; LoopLimit > i; i++)
            {
                // Do nothing...
            }
        }

        [Benchmark(Baseline = true)]
        [BenchmarkCategory("Variable operand")]
        public void IteratorLessThanVariable()
        {
            var loopLimit = LoopLimit;

            for (var i = 0; i < loopLimit; i++)
            {
                // Do nothing...
            }
        }

        [Benchmark()]
        [BenchmarkCategory("Variable operand")]
        public void VariableGreaterThanIterator()
        {
            var loopLimit = LoopLimit;

            for (var i = 0; loopLimit > i; i++)
            {
                // Do nothing...
            }
        }
    }
}

I did a little research beforehand to ensure that empty loops don't get optimized away and, according to Is there a way to get the .Net JIT or C# compiler to optimize away empty for-loops?, they don't. Here are the results I got on .NET Framework and .NET Core...

// * Summary *

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.18362
Intel Core i7 CPU 860 2.80GHz (Nehalem), 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=2.1.802
  [Host] : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT
  Clr    : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 64bit RyuJIT-v4.8.4010.0
  Core   : .NET Core 2.1.13 (CoreCLR 4.6.28008.01, CoreFX 4.6.28008.01), 64bit RyuJIT


|                      Method |  Job | Runtime |       Categories |    Mean |    Error |   StdDev | Ratio |
|---------------------------- |----- |-------- |----------------- |--------:|---------:|---------:|------:|
|    IteratorLessThanConstant |  Clr |     Clr | Constant operand | 1.285 s | 0.0063 s | 0.0059 s |  1.00 |
| ConstantGreaterThanIterator |  Clr |     Clr | Constant operand | 1.282 s | 0.0021 s | 0.0020 s |  1.00 |
|                             |      |         |                  |         |          |          |       |
|    IteratorLessThanVariable |  Clr |     Clr | Variable operand | 1.288 s | 0.0065 s | 0.0061 s |  1.00 |
| VariableGreaterThanIterator |  Clr |     Clr | Variable operand | 1.282 s | 0.0028 s | 0.0026 s |  1.00 |
|                             |      |         |                  |         |          |          |       |
|    IteratorLessThanConstant | Core |    Core | Constant operand | 1.286 s | 0.0082 s | 0.0077 s |  1.00 |
| ConstantGreaterThanIterator | Core |    Core | Constant operand | 1.287 s | 0.0072 s | 0.0067 s |  1.00 |
|                             |      |         |                  |         |          |          |       |
|    IteratorLessThanVariable | Core |    Core | Variable operand | 1.284 s | 0.0063 s | 0.0059 s |  1.00 |
| VariableGreaterThanIterator | Core |    Core | Variable operand | 1.286 s | 0.0075 s | 0.0071 s |  1.00 |

Based on the above results...

  • If you're asking if one operator is faster than the other, then I would say no.
  • If you're asking which operator you should use, I would suggest whichever one you feel gives the greatest readability and clarity to your code since that is much more important than any microoptimization, if one even exists.
Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
0

No, there isn't. But you should use the first one, as everyone does it.

CoderCharmander
  • 1,862
  • 10
  • 18