Reputation: 83
I recently started learning c# and learned that there are 2 ways to have my code output even numbers when I write this For loop
. I learned the syntax of version 2, which is intuitive to me. However, version 1 was an exampled I found elsewhere online. I want to understand if there is a difference between the two versions.
//Version 1
for (int num = 0; num < 100; num+=2)
{
Console.WriteLine (num);
}
//Version 2
for (int num = 0; num < 100; num++)
{
if (num % 2 == 0)
{
Console.WriteLine (num);
}
}
Of the two possible ways, is there any difference between the two syntaxes? If yes, which is more efficient and why?
Upvotes: 6
Views: 385
Reputation: 74227
For a given value of N (in your sample code, N=100)
N/2
additionsN
additions, plus N
integer divisions (a relatively expensive operation).And you forgot Version 3, bit-twiddling. Bitwise operations are a whole lot cheaper than division, and since we know that integers in the C# world are two's-complement binary values, the state of the low-order bit tells us whether an integer is even or not, thus:
bool isEven( int n ) { return 0 == ( n & 1 ) ; }
We can write a test harness, like this:
class Program
{
public static int Version1(int n)
{
int cnt = 0;
for ( int i = 0 ; i < n ; i+=2 )
{
++cnt;
}
return cnt;
}
public static int Version2(int n)
{
int cnt = 0;
for ( int i = 0 ; i < n ; ++i )
{
if ( i % 2 == 0 )
{
++cnt;
}
}
return cnt;
}
public static int Version3(int n)
{
int cnt = 0;
for ( int i = 0 ; i < n ; ++i )
{
if ( 0 == (i & 1) )
{
++cnt;
}
}
return cnt;
}
private static void Main(string[] args)
{
int n = 500000000;
Stopwatch timer = new Stopwatch();
timer.Start();
Version1( n );
timer.Stop();
Console.WriteLine( "{0:c} -- Version #1 (incrementing by 2)" , timer.Elapsed ) ;
timer.Restart();
Version2(n);
timer.Stop();
Console.WriteLine( "{0:c} -- Version #2 (incrementing by 1 with modulo test)" , timer.Elapsed ) ;
timer.Restart();
Version3(n);
timer.Stop();
Console.WriteLine( "{0:c} -- Version #3 (incrementing by 1 with bit twiddling)" , timer.Elapsed ) ;
return;
}
}
And find out which is actually faster. The above program runs the loop 500,000,000 times so we get numbers that are big enough to measure.
Here are the timings I get with VS 2013:
Debug build (non-optimized):
00:00:00.5500486 -- Version #1 (incrementing by 2)
00:00:02.0843776 -- Version #2 (incrementing by 1 with modulo test)
00:00:01.2507272 -- Version #3 (incrementing by 1 with bit twiddling)
Release build (optimized)
00:00:00.1680107 -- Version #1 (incrementing by 2)
00:00:00.5109271 -- Version #2 (incrementing by 1 with modulo test)
00:00:00.3367961 -- Version #3 (incrementing by 1 with bit twiddling)
Upvotes: 5
Reputation: 5357
This way is faster than method 1 and method 2 because recursion is faster than looping.
var sw3 = new System.Diagnostics.Stopwatch();
Action<int, int> printEvens = null;
printEvens = (index, count) =>
{
if (index % 2 == 0)
Console.WriteLine(index.ToString());
if (index < count)
printEvens(++index, count);
};
sw3.Start();
printEvens(0, 100);
sw3.Stop();
The output on my machine is..
Method 1: 96282 Method 2: 184336 Method 3: Recursion 59188
Upvotes: 0
Reputation: 3526
Version 1 is "faster" from a pure analysis viewpoint (independent of compilation optimizations). But as dbarnes mentioned in the comments to your question, what you code in C# and what comes out the other side of the compiler may be completely different. Version 2 is "slower" because it has more loop iterations to cycle through, and it has slightly larger code complexity with that if-statement.
Don't concern yourself too much with optimization at first (it is called "premature optimization" to be concerned with performance before you know it exists and can prove that it is a problem worth solving). Simply code to learn, then refactor, then look into performance issues if any exist.
In fact, I'd speculate that the compiler could be configured to "unroll" both of those loops: it gets rid of the looping and simply duplicates the loop body 50 or 100 times for version 1 or 2 respectively.
Upvotes: 3
Reputation: 81
Version 1 is more efficient. Because "version 2" takes one more comparison than "version 1", while "version 1" takes two comparisons.
//Version 1
for (int num = 0; num < 100; num+=2) // Two comparisons
{
Console.WriteLine (num);
}
//Version 2
for (int num = 0; num < 100; num++) // Two comparisons
{
if (num % 2 == 0) // One comparison
{
Console.WriteLine (num);
}
}
Upvotes: 1
Reputation: 205
You can exactly measure which method is faster, on a precision of 10000th of a millisecond, also known as "Tick" in the .Net framework.
This is done by using the Stopwatch class in the System.Diagnostic namespace:
var sw1 = new System.Diagnostics.Stopwatch();
var sw2 = new System.Diagnostics.Stopwatch();
//Version 1
sw1.Start();
for (int num = 0; num < 100; num += 2)
{
Console.WriteLine(num);
}
sw1.Stop();
//Version 2
sw2.Start();
for (int num = 0; num < 100; num++)
{
if (num % 2 == 0)
{
Console.WriteLine(num);
}
}
sw2.Stop();
Console.Clear();
Console.WriteLine("Ticks for first method: " + sw1.ElapsedTicks);
Console.WriteLine("Ticks for second method: " + sw2.ElapsedTicks);
The output will show that the first method is faster.
Why is this the case?
In the first version, ignoring the console output, there is only one operation performed (+= 2
) and in the end, the program goes through 50 cycles of the loop.
In the second version, it needs to do two operations (++
and % 2
) and one more comparison (num % 2 == 0
) in addition to 100 cycles in the loop.
If you measure the program exactly like this, then it will have a large difference in time, like multiple milliseconds. This is because the Console.WriteLine is actually taking up a lot of time. Since it's done 50 times more in the second version, it takes much more time. If you want to measure the algorithm alone, omit the console output.
If you do that, the difference in ticks on my machine is 24 ticks to 43 ticks, on average.
So in conclusion, the first method is more efficient, by about 19/10000 milliseconds.
Upvotes: 3
Reputation: 1697
Actually the adding mechanism ( Version 1 ) is a little better
The result of the addition was better than the modulus(the %) by 0.0070000 milliseconds over the course of 2 million or 200,000 iterations
But seriously… unless you have a mission critical micro-optimization need, stick with the modulus operator for easy to read code rather than trying to save roughly 00.0070000 milliseconds execution time.
Upvotes: 2
Reputation: 1550
Version 1 is more efficient in the sense that it iterates half as many times with the same output. Version 1 will iterate 50 times where as version 2 will iterate 100 times but only print half the results. However, I think the second shows your intentions better.
Upvotes: 1