Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

int operators != and == when comparing to zero

I've found that != and == are not the fastest ways for testing for zero or non-zero.

bool nonZero1 = integer != 0; xor eax, eax test ecx, ecx setne al  bool nonZero2 = integer < 0 || integer > 0; test ecx, ecx setne al  bool zero1 = integer == 0; xor eax, eax test ecx, ecx sete al  bool zero2 = !(integer < 0 || integer > 0); test ecx, ecx sete al 

Compiler: VC++ 11 Optimization flags: /O2 /GL /LTCG

This is the assembly output for x86-32. The second versions of both comparisons were ~12% faster on both x86-32 and x86-64. However, on x86-64 the instructions were identical (first versions looked exactly like the second versions), but the second versions were still faster.

  1. Why doesn't the compiler generate the faster version on x86-32?
  2. Why are the second versions still faster on x86-64 when the assembly output is identical?

EDIT: I've added benchmarking code. ZERO: 1544ms, 1358ms NON_ZERO: 1544ms, 1358ms http://pastebin.com/m7ZSUrcP or http://anonymouse.org/cgi-bin/anon-www.cgi/http://pastebin.com/m7ZSUrcP

Note: It's probably inconvenient to locate these functions when compiled in a single source file, because main.asm goes quite big. I had zero1, zero2, nonZero1, nonZero2 in a separate source file.

EDIT2: Could someone with both VC++11 and VC++2010 installed run the benchmarking code and post the timings? It might indeed be a bug in VC++11.

like image 481
NFRCR Avatar asked May 31 '12 17:05

NFRCR


People also ask

Which is not equal to a comparison operator?

The not-equal-to operator ( != ) returns true if the operands don't have the same value; otherwise, it returns false .

What are the six comparison operators?

A comparison operator compares two values and returns a boolean value, either True or False . Python has six comparison operators: less than ( < ), less than or equal to ( <= ), greater than ( > ), greater than or equal to ( >= ), equal to ( == ), and not equal to ( != ).

Which is the comparison operator?

Comparison operators can compare numbers or strings and perform evaluations. Expressions that use comparison operators do not return a number value as do arithmetic expressions. Comparison expressions return either 1 , which represents true, or 0 , which represents false.


1 Answers

This is a great question, but I think you've fallen victim to the compiler's dependency analysis.

The compiler only has to clear the high bits of eax once, and they remain clear for the second version. The second version would have to pay the price to xor eax, eax except that the compiler analysis proved it's been left cleared by the first version.

The second version is able to "cheat" by taking advantage of work the compiler did in the first version.

How are you measuring times? Is it "(version one, followed by version two) in a loop", or "(version one in a loop) followed by (version two in a loop)"?

Don't do both tests in the same program (instead recompile for each version), or if you do, test both "version A first" and "version B first" and see if whichever comes first is paying a penalty.


Illustration of the cheating:

timer1.start(); double x1 = 2 * sqrt(n + 37 * y + exp(z)); timer1.stop(); timer2.start(); double x2 = 31 * sqrt(n + 37 * y + exp(z)); timer2.stop(); 

If timer2 duration is less than timer1 duration, we don't conclude that multiplying by 31 is faster than multiplying by 2. Instead, we realize that the compiler performed common subexpression analysis, and the code became:

timer1.start(); double common = sqrt(n + 37 * y + exp(z)); double x1 = 2 * common; timer1.stop(); timer2.start(); double x2 = 31 * common; timer2.stop(); 

And the only thing proved is that multiplying by 31 is faster than computing common. Which is hardly surprising at all -- multiplication is far far faster than sqrt and exp.

like image 131
Ben Voigt Avatar answered Sep 19 '22 18:09

Ben Voigt