Greater Than vs Less Than vs Equals in C#
As a programmer, have you ever had a situation where there’s a variable that could be 1 of 2 or maybe 3 values? I came across code where there was a variable “x”, which could be -1, 0, or 1. In testing for values, the code had simple logic which made sense:
1 2 3 4 5 6 7 |
if (x > 0) { //it did something } if (x == 0) { //it did something } |
While the above code works, since we know the finite number of values x can be, what if we tweaked it to the following:
1 2 3 4 5 6 7 |
if (x == 1) { //it did something } if (x == 0) { //it did something } |
Greater Than vs Less Than vs Equals.
We don’t give much thought to it. Both code samples are just as easily readable above.
So that’s when this Curious Consultant started wondering what’s faster?
in C# logic constructs.
Does it even make a difference?
Let’s find out!
The Nuts and Bolts
There isn’t anything complicated or fancy about this test.
It is written in Visual Studio 2017 targeting .Net Framework version 4.7.1 x64. The source code is available at the end of this blog so you can benchmark it on your own system.
In a nutshell, the code does the following:
- Loops a specified number of times using the comparison operator
- If it meets the comparison criteria, the running total is incremented by 1.
Assumptions:
- No exception handling as no exceptions should occur
The exe file was run under Windows 10 Professional 64-bit with 32GB of memory.
The test was run for the following number of comparisons:
- 100
- 1,000
- 10,000
- 100,000
- 1,000,000
- 10,000,000
- 100,000,000
Line Up the Starting Positions
These tests were run a few times, but to be honest I didn’t feel like documenting every single one. The results were all similar, so I just took the times from one of the middle runs.
All times are indicated in seconds.milliseconds format. Lower numbers indicate faster run time performance.
Winners are highlighted in green; there are no points for second place.
The Results Are Interesting, but Consistent:
Have a look over the results. Each set is consistent. That is,
- if x is 1, the test x == 1 performed better than x > 0
- if x is -1, the test x == -1 performed better than x < 0
|
Number of Runs |
||||||
|
100 |
1,000 |
10,000 |
100,000 |
1,000,000 |
10,000,000 |
100,000,000 |
where x is -1 |
|||||||
x < 0 |
00.0000004 |
00.0000018 |
00.0000145 |
00.0001435 |
00.0014923 |
00.0161081 |
00.1599993 |
x == -1 |
00.0000004 |
00.0000014 |
00.0000108 |
00.0001053 |
00.0012375 |
00.0118365 |
00.1089501 |
|
|||||||
where x is 1 |
|||||||
x > 0 |
00.0000004 |
00.0000017 |
00.0000165 |
00.0001434 |
00.0014903 |
00.0156466 |
00.1737996 |
x == 1 |
00.0000005 |
00.0000014 |
00.0000264 |
00.0001054 |
00.0010915 |
00.0121319 |
00.1103028 |
In Summary:
While the time differences probably aren’t significant enough to notice running an application, as the number of iterations gets higher, “==” definitely outperforms it’s respecting “<” or “>” comparison.
Is x > 0 any easier or harder to read or maintain than x == 1?
No. User preference.
However, if there’s a need to squeeze every last little microsecond possible, it’s best to stick with the “==” comparison operator where it makes sense.
The Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
using System; using System.Collections.Generic; using System.Collections; using System.Collections.Concurrent; using System.Data; using System.Data.Sql; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Threading; using System.Diagnostics; namespace TestApplication { class Program { static void Main(string[] args) { DateTime end; DateTime start = DateTime.Now; Console.WriteLine("### Overall Start Time: " + start.ToLongTimeString()); Console.WriteLine(); TestGreaterLessThanVsEquals(100, -1); TestGreaterLessThanVsEquals(1000, -1); TestGreaterLessThanVsEquals(10000, -1); TestGreaterLessThanVsEquals(100000, -1); TestGreaterLessThanVsEquals(1000000, -1); TestGreaterLessThanVsEquals(10000000, -1); TestGreaterLessThanVsEquals(100000000, -1); TestGreaterLessThanVsEquals(100, 1); TestGreaterLessThanVsEquals(1000, 1); TestGreaterLessThanVsEquals(10000, 1); TestGreaterLessThanVsEquals(100000, 1); TestGreaterLessThanVsEquals(1000000, 1); TestGreaterLessThanVsEquals(10000000, 1); TestGreaterLessThanVsEquals(100000000, 1); end = DateTime.Now; Console.WriteLine(); Console.WriteLine("### Overall End Time: " + end.ToLongTimeString()); Console.WriteLine("### Overall Run Time: " + (end - start)); Console.WriteLine(); Console.WriteLine("Hit Enter to Exit"); Console.ReadLine(); } //#################################################### //Compares whether it's faster to do something like , if x is 1: x > 0 or x == 1. //Code from http://cc.davelozinski.com static void TestGreaterLessThanVsEquals(int numberOfComparisons, int valueToCompareTo) { Console.WriteLine("######## " + System.Reflection.MethodBase.GetCurrentMethod().Name); Console.WriteLine("Number of comparisons: " + numberOfComparisons.ToString("#,##0")); Stopwatch sw = new Stopwatch(); DateTime end = DateTime.Now; DateTime start = DateTime.Now; int totalSum = 0; Console.WriteLine("###########################################################"); Console.WriteLine("if value (" + valueToCompareTo + ") > 0 test " + numberOfComparisons.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfComparisons; x++) { if (valueToCompareTo > 0) totalSum += 1; } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Console.WriteLine("Sum is: " + totalSum.ToString("#,##0")); totalSum = 0; Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("if value (" + valueToCompareTo + ") < 0 test " + numberOfComparisons.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfComparisons; x++) { if (valueToCompareTo < 0) totalSum += 1; } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Console.WriteLine("Sum is: " + totalSum.ToString("#,##0")); totalSum = 0; Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("if value (" + valueToCompareTo + ") == " + valueToCompareTo + " test " + numberOfComparisons.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfComparisons; x++) { if (valueToCompareTo == 2) totalSum += 1; } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Console.WriteLine("Sum is: " + totalSum.ToString("#,##0")); Thread.Sleep(500); Console.WriteLine(); } } //class } //namespace |