If you're going to use a ternary operator, you probably want to assign its result:
x = (x % 2 == 0) ? 2 * x : x;
Personally, I think I'd just use a tiny bit of math:
x <<= ((x & 1) ^ 1);
x&1
gives the least significant bit of x
, which will be 1 if x is odd, and 0 if it's even. The ^ 1
part flips that bit, so it gives 1 if x
was even and 0 if x
was odd. We then shift x
left by that many bits. Shifting by 0 bits obviously leaves x
unchanged. Shift left one bit multiplies x
by 2.
As for why the latter would (or at least might) be preferable, it mostly comes down to a question of whether you really care about performance in this situation. If you're in situation where performance doesn't matter, then something like if ((x%2)==0) x *= 2;
is probably your best choice.
I'd at least guessed that at least part of the reason for the question was a concern for efficiency though. If so, the purely mathematical method is likely to be a better choice. For example, let's consider the code VC++ produces for the two:
; mathematical version:
mov eax, DWORD PTR _x$[esp-4]
mov ecx, eax
not ecx
and ecx, 1
shl eax, cl
[note: for this source code, g++ produces nearly identical object code].
Ignoring the (possible) time to load x
from memory, this should execute in no more than 4 clock cycles on just about any Intel processor going back to around the 386. Better still, I'd expect just about any compiler for any processor to produce pretty similar results -- a straightforward, literal translation from the source code to assembly language for nearly any reasonable processor is going to do the actual math in four instructions, each of which is about as simple and fast as possible.
The version using the if
statement comes out like this:
; Line 2
mov ecx, DWORD PTR _x$[esp-4]
mov eax, ecx
and eax, -2147483647 ; 80000001H
jns SHORT $LN5@f
dec eax
or eax, -2 ; fffffffeH
inc eax
$LN5@f:
lea eax, DWORD PTR [ecx+ecx]
je SHORT $LN1@f
; Line 3
mov eax, ecx
$LN1@f:
As compiling goes, this isn't too bad. It's at least avoiding the div
that would be the obvious way of implementing a %2
. Unfortunately, it's still not really smart enough to be competitive -- it still has a couple of branches, one of which probably won't be very predictable, so around half the time we'll pay the price of a mispredicted branch.
Depending on the compiler, you can (and will) see better than this. For example using g++ instead, I get this:
mov eax, DWORD PTR [ebp+8]
and eax, 1
test eax, eax
jne L2
sal DWORD PTR [ebp+8]
L2:
mov eax, DWORD PTR [ebp+8]
While certainly better than VC++ did for this code, that's still nowhere near as good as the mathematical version. In particular, unless that least significant bit is fairly predictably even or odd, that branch is likely to be mi-predicted about half the time.
Bottom line: at very best, this might come close to matching the mathematical version -- but that'll depend both on the compiler and the input data cooperating. With anything but the most fortuitous combination of compiler and input data, it'll almost certainly be slower by at least 2x, and 10x wouldn't be even mildly surprising.
Of course, depending on what flags, compiler version, etc., I use, I might be able to get better results out of either compiler than I actually did. With some persistence, I might even get results equal to the mathematical version of the code. Unless I knew the target compiler and CPU pretty well, I'd be pretty uncertain about even getting as good of results though -- and chances of them being better strike me as extremely slim at best.