I need the most efficient way (in cpu cycles) to determine if two numbers have the same/different sign. But the catch is if either number is zero I need to be able to distinguish it from numbers with same/different signs (ie. zero is treated as a "third" sign). The following code is similar to what I need, but the return values can be anything as long as there are only three distinct return values.
int foo(int x, int y) {
if (x * y > 0) return 1;
if (x * y < 0) return -1;
return 0;
}
For my specific problem, the values are in the range [-6, 6] and X is guaranteed to not be 0. I found a solution to find if two numbers have the same sign, and altered it to get the following solution.
return y? (((x^y) >= 0)? 1 : -1) : 0;
There should be some bitops/comparisons that give faster results than using multiplication, branching, comparisons.
Here is another version (with ugly, non-portable bit manipulation tricks):
int foo(int x, int y) {
return ((x^y) >> 4) - ((x^(-y)) >> 4);
}
Some explanations:
((x^y) >> 4)
is -1 if exactly one of x and y is negative, otherwise it is 0.((x^(-y)) >> 4)
is -1 if exactly one of x and -y is negative, otherwise it is 0.Assumes two's complement arithmetic and assumes that >> shifts with sign-extension.
How about:
int foo(int x,int y)
{
// As suggested by Luther Blissett below in the comments.
// Increased the size of the array to 16x16.
// This allows for simpler optimization for the compiler
// Also use +8 rather +6 in the hopes that compiler optimization will be easier
// you never know (there may be some fancy trick.
static int sign[16][16] = {
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 1, 1, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, -1, -1, -1, -1},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1},
{ -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1}
};
return sign[x+8][y+8];
}
This should be fast as there is no branching that will stall the processor.
Using g++ -O3 -S:
__Z3fooii:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl 12(%ebp), %edx
popl %ebp
sall $4, %eax
addl %edx, %eax
movl _ZZ3fooiiE4sign+544(,%eax,4), %eax
ret
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With