Comparing by greater or equal can have a cost in processor cycles greater than just comparing with greater. As long as this operation is actually done.
Understand that it is common that in machine language you have an instruction to make one or the other operator. You don’t need more than one of them to find the result. But that doesn’t mean that the cost is the same.
One thing that a lot of people don’t understand is that code size and cost to execute are very different things. If short code were faster, just write Execute()
and would do everything you want as quickly as possible :) There is no magic, even at a low level that is all bit manipulation some operations need a few steps to get the result, just like you would on paper or in your head. These steps are execution cycles (each processor’s Hertz). The thing is a bit more complicated than that because of the pipeling processor that can perform various things together (nothing to do with thread), but there’s no point in getting into it here.
It is also important to understand that the compiler can in some cases optimize high-level code to change the operator and use the one that will run faster. You don’t need to know that. Of course he can not always ensure that a change will not affect the execution and only with guarantees that the optimization will not create problem is that he would do. I’m not saying that the C# compiler does, but could do.
See the two codes as it would look on CIL (is not yet the machine code, which depends on where it will be executed, but already gives a basis). The Jitter could optimize at the time of execution:
.method public hidebysig static void Main(string[] args) cil managed {
//
.maxstack 2
.locals init (int32 V_0,
int32 V_1,
bool V_2,
bool V_3)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldc.i4.2
IL_0005: clt //<=========== operador aqui
IL_0007: ldc.i4.0
IL_0008: ceq //<=========== operador aqui
IL_000a: stloc.2
IL_000b: ldloc.2
IL_000c: brfalse.s IL_001b
IL_000e: nop
IL_000f: ldstr "Maior ou igual"
IL_0014: call void [mscorlib]System.Console::WriteLine(string)
IL_0019: nop
IL_001a: nop
IL_001b: ldc.i4.2
IL_001c: stloc.1
IL_001d: ldloc.1
IL_001e: ldc.i4.1
IL_001f: cgt //<=========== operador aqui
IL_0021: stloc.3
IL_0022: ldloc.3
IL_0023: brfalse.s IL_0032
IL_0025: nop
IL_0026: ldstr "Maior"
IL_002b: call void [mscorlib]System.Console::WriteLine(string)
IL_0030: nop
IL_0031: nop
IL_0032: ret
}
Which was compiled from:
public static void Main (string [] args) {
int x = 2;
if (x >= 2) WriteLine("Maior ou igual");
int y = 2;
if (y > 1) WriteLine("Maior");
}
I put in the Github for future reference.
Note that CIL preferred to have two instructions to perform the operation (clt
and ceq
). This does not mean that the machine code will do the same, it depends on how Jitter will create the native code. Note also that he preferred to invert the comparison to give the desired result.
It is likely that using the simple operator gives a better performance, but this is not guaranteed. There are other more important things to optimize that will give greater gain. Much more.
Obviously that goes for int
, if it has decimal part it is clear that they do not do the same thing. So I usually try to use the most appropriate semantics and only worry about the performance in case so if I measure that accurate have this minimum gain of a few cycles.
I was researching and saw that in most current architectures (in my time it did) it makes no difference to use one operator or the other, they perform in the same amount of cycles. It is not easy to guarantee anything because even the processor does optimizations.
I did some tests that are not the ideals (I’m not even going to post it because it tests other things than this operation) and the only conclusion I’ve had is that it really doesn’t make a difference. There is a case that has come to give huge differences to one side or the other, which shows that even the momentary environment influences more than the individual operation. Where it will be used will also influence. Today except in very heavy mathematical calculations what runs on the processor makes very little difference, expensive is accessing memory, that’s what you have to worry about.
Something tells me that these differences have to do even indirectly with the effect of Spectre and Meltdown.
Has a question in the OS who speaks of it in detail. Don’t know English? This subject shouldn’t interest you then.
Perhaps there will be some crazy answers from people who have not read the question. Anyway, I found interesting this +1
– Jéf Bueno
Thinking of this example of yours, the only reason to use the
>=
, would be to "facilitate" understanding. But I believe that the right thing would be not to use magic numbers, and that breaks with the argument of "facilitating" understanding. Thinking about it, it seems as if the>=
is unnecessary. What an intriguing question. + 1– Victor Tadashi
Excellent question, great answers. It is the same as asking why to use "int" and not "Int32" or when to use "==" and not "Equals". There are controversies! My opinion: from a practical point of view write the code that is easier to understand.
– Fabio Silva Lima
The analogy was not happy, it is not the same thing. Opinions do not help answer, give facts.
– Maniero