Reputation: 3941
I wonder if there is a difference in performance between
checking if a value is greater / smaller than another
for(int x = 0; x < y; x++); // for y > x
and
checking if a value is not equal to another
for(int x = 0; x != y; x++); // for y > x
and why?
In addition: What if I compare to zero, is there a further difference?
It would be nice if the answers also consider an assebled view on the code.
EDIT: As most of you pointed out the difference in performance of course is negligible but I'm interested in the difference on the cpu level. Which operation is more complex?
To me it's more a question to learn / understand the technique.
I removed the Java
tag, which I added accidentally because the question was meant generally not just based on Java, sorry.
Upvotes: 52
Views: 25063
Reputation: 89
The performance in theory is the same. When you do a less than or not equal to operation, in the processor level you actually perform a subtract operation and check if the negative flag or zero flag is enabled in the result. In theory the performance will be the same. Since the difference is only checking the flag set.
Upvotes: 3
Reputation: 3941
Now 6 years later and after still receiving occasional notifications from this question I'd like to add some insights that I've gained during my computer science study.
Putting the above statements into a small program and compiling it...
public class Comp {
public static void main(String[] args) {
int y = 42;
for(int x = 0; x < y; x++) {
// stop if x >= y
}
for(int x = 0; x != y; x++) {
// stop if x == y
}
}
}
... we get the following bytecode:
public static void main(java.lang.String[]);
Code:
// y = 42
0: bipush 42
2: istore_1
// first for-loop
3: iconst_0
4: istore_2
5: iload_2
6: iload_1
7: if_icmpge 16 // jump out of loop if x => y
10: iinc 2, 1
13: goto 5
// second for-loop
16: iconst_0
17: istore_2
18: iload_2
19: iload_1
20: if_icmpeq 29 // jump out of loop if x == y
23: iinc 2, 1
26: goto 18
29: return
As we can see, on bytecode level both are handled in the same way and use a single bytecode instruction for the comparison.
As already stated, how the bytecode is translated into assembler/machine code depends on the JVM. But generally this conditional jumps can be translated to some assembly code like this:
; condition of first loop
CMP eax, ebx
JGE label ; jump if eax > ebx
; condition of second loop
CMP eax, ebx
JE label ; jump if eax == ebx
On hardware level JGE and JE have the same complexity.
So all in all: Regarding performance, both x < y
and x != y
are theoretically the same on hardware level and one isn't per se faster or slower than the other.
Upvotes: 20
Reputation: 131
Other people seem to have answered from a measured perspective, but from the machine level you'd be interested in the Arithmetic Logic Unit (ALU), which handles the mathy bits on a "normal computer". There seems to be a pretty good detail in How does less than and greater than work on a logical level in binary? for complete details.
From purely a logical level, the short answer is that it's easier to tell if something is not something than it is to tell if something is relative to something, however this has likely been optimized in your standard personal computer or server, so you'll only see actual gains likely in small personal builds like on-board computers for drones or other micro-technologies.
Upvotes: 5
Reputation: 1
Wonder if nested for each test, same results ?
for(int x = 0; x < y; x++)
{
for(int x2 = 0; x2 < y; x2++) {}
}
for(int x = 0; x != y; x++)
{
for(int x2 = 0; x2 != y; x2++) {}
}
Upvotes: -5
Reputation: 8284
The performance is absolutely negligible. Here's some code to prove it:
public class OpporatorPerformance {
static long y = 300000000L;
public static void main(String[] args) {
System.out.println("Test One: " + testOne());
System.out.println("Test Two: " + testTwo());
System.out.println("Test One: " + testOne());
System.out.println("Test Two: " + testTwo());
System.out.println("Test One: " + testOne());
System.out.println("Test Two: " + testTwo());
System.out.println("Test One: " + testOne());
System.out.println("Test Two: " + testTwo());
}
public static long testOne() {
Date newDate = new Date();
int z = 0;
for(int x = 0; x < y; x++){ // for y > x
z = x;
}
return new Date().getTime() - newDate.getTime();
}
public static long testTwo() {
Date newDate = new Date();
int z = 0;
for(int x = 0; x != y; x++){ // for y > x
z = x;
}
return new Date().getTime() - newDate.getTime();
}
}
The results:
Test One: 342
Test Two: 332
Test One: 340
Test Two: 340
Test One: 415
Test Two: 325
Test One: 393
Test Two: 329
Upvotes: 16
Reputation: 533820
You should still do what is clearer, safer and easier to understand. These micro-tuning discussions are usually a waste of your time because
Note: the machine generated can also change with processor or JVM, so looking this is not very helpful in most cases, even if you are very familiar with assembly code.
What is much, much more important is the maintainability of the software.
Upvotes: 41
Reputation: 65869
There is rarely a performance hit but the first is much more reliable as it will handle both of the extraordinary cases where
Upvotes: 5