tags:

views:

302

answers:

5

A friend just throw some code similar to following C# code:

int i = ...;
return i < 0 ? 0 : i;

That made me think. There's any "different" way to return zero for negative integers, or current positive value? More specifically I'm looking for bitwise operations, if possible.

BTW, I'm aware of Math.Max(0, i);

+2  A: 

Short answer: No.

Bit operators do something very different, or rather are used for different problems.

If you know the size of your integers, you could test the highest (most significant) bit; if it's 1, the number is negative and you can act on that. But that would be a heck of a lot more work than the simple "<" test.

Carl Smotricz
And I wouldn't be surprised if the compiler already does this optimization.
Kai
+6  A: 

What's wrong with Math.Max?

You can do the equivalent without a branch using bitwise operations:

r = x ^ ((x ^ y) & -(x < y)); // == max(x, y)

If you substitute zero, it collapses to:

r = (y & -(0 < y)); // == max(0, y)

(Source: this list of bitwise tricks.)

If branches were extremely expensive on your platform, that might be worthwhile in some inner loop, I suppose, but it's pretty obscure and not the kind of thing I'd like to come across outside of an extremely time-sensitive function.

Tim Sylvester
Generally (x < y) is going to require a branch to convert it to either 0/1.
Aaron
That's only true on some platforms. Most have a compare instruction the result of which can be moved or shifted into a general purpose register.
Tim Sylvester
@Aaron, Not true x86 is a **very** rich instruction set.
Frank Krueger
True - I just tried it and msdev used the 'setg' instruction -- so no branch necessary.
Aaron
If MS's JIT is smart enough, Math.Max should already do just that.
LiraNuna
Grizzly
@Grizzly True that will generate a branch in CIL code. For the `max(0,y)` case, though, you could replace the C expression `-(0 < y)` with the C# expression `-(int)(((uint)y >> (8 * sizeof(int) - 1)) ^ 1)`, which would generate 5 or so CIL instructions and no branches. As if it wasn't ugly enough already...
Tim Sylvester
+2  A: 

Not bitwise but different:

return (i + Math.abs(i))/2

EDIT:

return (int)(i/2f + Math.abs(i)/2f)
Kai
Kinky, but my overflow-sense is tickling :)
cwap
yep, you're right
Kai
+4  A: 

How about:

int i = ...;

return i & ~(i >> 31);

Aaron
Fails for i = int.MinValue.
Dan Blanchard
Good point - I modified it - it should now work for all cases.
Aaron
Argh same strategy but much cleaner than mine. Didn't know the ~ to be honest
Rune FS
+2  A: 

The below will do the trick and the code reads so well it practically don't need a comment ;)

((((0x80000000 & i) >> 31)^1) * 0xFFFFFFFF) & i

then again

int temp = (0x80000000 & i); //get the most significant bit (1 for negative 0 for positive)
temp = (temp>>31)^1; //more it to the least significant and not it (we now have 0 for negative numbers and one for positive)

temp *= 0xFFFFFFFF; //get a lof of F's if it's positive or a lot of zeros if the number was negative

temp = temp & i; //and the F's/zeros with the original number

and voila zero for all negative number and all positive are left unchanged

Rune FS