Using ONLY:
! ~ & ^ | + << >>
NO LOOPS
I need to determine the sign of a 32 bit integer and I need to return 1 if positive, 0 if 0 and -1 if ne
Try this:
(x >> 31) | (((0 - x) >> 31) & 1)
How about this:
(x >> 31) | (((~x + 1) >> 31) & 1)
EDIT 2:
In response to issues (or rather nit-picking) raised in the comments...
Assumptions for these solutions to be valid:
0
is the same type as x.If conditionals (not if
statements) and subtraction are allowed, the simplest & cleaner solution (IMO) is:
int sign = (v > 0) - (v < 0);
Not using subtraction (and assuming int
is 32 bits):
#include <stdio.h>
#include <assert.h>
#include <limits.h>
int process(int v) {
int is_negative = (unsigned int)v >> 31; // or sizeof(int) * CHAR_BIT - 1
int is_zero = !v;
int is_positive = !is_negative & !is_zero;
int sign = (is_positive + ~is_negative) + 1;
return sign;
}
int main() {
assert(process(0) == 0);
printf("passed the zero test\n");
for (int v = INT_MIN; v < 0; v++) {
assert(process(v) == -1);
}
printf("passed all negative tests\n");
for (int v = 1; v < INT_MAX; v++) {
assert(process(v) == +1);
}
printf("passed all positive tests\n");
return 0;
}
Here's are the results:
$ gcc -o test test.c -Wall -Wextra -O3 -std=c99 && ./test && echo $#
passed zero test
passed all negative tests
passed all positive tests
0
Why do you need to use bitwise operators for that?
int get_sign(int value)
{
return (value < 0) ? -1 : (int)(value != 0);
}
If you absolutely have to use bitwise operators, then you can use the &
operator to check for negative values, no shifting needed:
int get_sign(int value)
{
return (value & 0x80000000) ? -1 : (int)(value != 0);
}
If you want to shift:
int get_sign(int value)
{
return ((value >> 31) & 1) ? -1 : (int)(value != 0);
}
I'm not sure this is the absolute ideal way to do things, but I think it's reasonably portable and at least somewhat simpler than what you had:
#define INT_BITS 32
int sign(int v) {
return (!!v) | -(int)((unsigned int)v >> (INT_BITS-1));
}
Assuming the implementation defines arithmetic right shift:
(x>>31) | !!x
Unlike Mystical's answer, there is no UB.
And, if you want to also support systems where right shift is defined to be arithmetic shift:
~!(x>>31)+1 | !!x
Edit: Sorry, I omitted a !
in the second version. It should be:
~!!(x>>31)+1 | !!x
This version is still dependent on the implementation being twos complement and having either arithmetic or logical right-shift, i.e. if the implementation-defined behavior were something else entirely it could break. However, if you change the types to unsigned types, all of the implementation-defined behavior vanishes and the result is -1U
, 0U
, or 1U
depending on the "sign" (high bit and zero/nonzero status) of x
.
A bit more convoluted, but there is this:
(~((x >> 31) & 1) + 1) | (((~x + 1) >> 31) & 1)
This should take care of the ambiguity of whether the shift will fill in 1's or 0's
For a breakdown, any place we have this construct:
(z >> 31) & 1
Will result in a 1 when negative, and a 0 otherwise.
Any place we have:
(~z + 1)
We get the negated number (-z)
So the first half will produce a result of 0xFFFFFFFF (-1) iff x is negative, and the second half will produce 0x00000001 (1) iff x is positive. Bitwise or'ing them together will then produce a 0x00000000 (0) if neither is true.