32

I can check whether a number is odd/even using bitwise operators. Can I check whether a number is positive/zero/negative without using any conditional statements/operators like if/ternary etc.

Can the same be done using bitwise operators and some trick in C or in C++?

Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
Anirudhh Er
  • 321
  • 1
  • 3
  • 3
  • 1
    When you check for odd/even you may want to do a bitwise check to eliminate the division (in case your compiler is so dumb). But **why** to check the sign this way??? – Yakov Galka Sep 23 '10 at 14:51
  • 2
    Please state the number format. Integers? Floats? What kind of integers/floats? Two's complement? Sign+Magnitude? IEEE-754? Be specific. – sellibitze Sep 23 '10 at 15:03

18 Answers18

31

Can I check whether a number is positive/zero/negative without using any conditional statements/operators like if/ternary etc.

Of course:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
Yakov Galka
  • 70,775
  • 16
  • 139
  • 220
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
20

If the high bit is set on a signed integer (byte, long, etc., but not a floating point number), that number is negative.

int x = -2300;  // assuming a 32-bit int

if ((x & 0x80000000) != 0)
{
    // number is negative
}

ADDED:

You said that you don't want to use any conditionals. I suppose you could do this:

int isNegative = (x & 0x80000000);

And at some later time you can test it with if (isNegative).

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
  • 6
    Floating-point numbers nowadays tend to be in the IEEE format, which does have an explicit sign bit. – David Thornley Sep 23 '10 at 14:13
  • @David: I didn't know that. Do you know which bit is the sign bit? – Jim Mischel Sep 23 '10 at 14:14
  • @Jim Mischel: according to this page: http://en.wikipedia.org/wiki/Double_precision_floating-point_format, it is also the high bit. – Evan Teran Sep 23 '10 at 14:16
  • It's the highest bit for IEEE 754 floats also. `1 << sizeof(yourfloat)*8-1` should get you the mask to use in any case. – Matt K Sep 23 '10 at 14:16
  • Will this logic change for little endian vs big endian machines? – Chubsdad Sep 23 '10 at 14:38
  • @Chubsdad: no. Big/little endian is strictly about the order of bytes in memory. When computation is done, a value is treated as a single unit and the sign bit is always the high bit. (On modern processors.) – Jim Mischel Sep 23 '10 at 14:42
  • 1
    This is wrong, sorry. If a machine uses 1-complement signed integers or sign–magnitude signed integers, which both can be C-compliant, the highest bit can be set for 0. – 12431234123412341234123 Aug 25 '20 at 12:30
13

Or, you could use signbit() and the work's done for you.

I'm assuming that under the hood, the math.h implementation is an efficient bitwise check (possibly solving your original goal).

Reference: http://en.cppreference.com/w/cpp/numeric/math/signbit

William Denniss
  • 16,089
  • 7
  • 81
  • 124
11

There is a detailed discussion on the Bit Twiddling Hacks page.

int v;      // we want to find the sign of v
int sign;   // the result goes here 

// CHAR_BIT is the number of bits per byte (normally 8).
sign = -(v < 0);  // if v < 0 then -1, else 0. 
// or, to avoid branching on CPUs with flag registers (IA32):
sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// or, for one less instruction (but not portable):
sign = v >> (sizeof(int) * CHAR_BIT - 1); 

// The last expression above evaluates to sign = v >> 31 for 32-bit integers.
// This is one operation faster than the obvious way, sign = -(v < 0). This
// trick works because when signed integers are shifted right, the value of the
// far left bit is copied to the other bits. The far left bit is 1 when the value
// is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior
// is architecture-specific.

// Alternatively, if you prefer the result be either -1 or +1, then use:

sign = +1 | (v >> (sizeof(int) * CHAR_BIT - 1));  // if v < 0 then -1, else +1

// On the other hand, if you prefer the result be either -1, 0, or +1, then use:

sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));
// Or, for more speed but less portability:
sign = (v != 0) | (v >> (sizeof(int) * CHAR_BIT - 1));  // -1, 0, or +1
// Or, for portability, brevity, and (perhaps) speed:
sign = (v > 0) - (v < 0); // -1, 0, or +1

// If instead you want to know if something is non-negative, resulting in +1
// or else 0, then use:

sign = 1 ^ ((unsigned int)v >> (sizeof(int) * CHAR_BIT - 1)); // if v < 0 then 0, else 1

// Caveat: On March 7, 2003, Angus Duggan pointed out that the 1989 ANSI C
// specification leaves the result of signed right-shift implementation-defined,
// so on some systems this hack might not work. For greater portability, Toby
// Speight suggested on September 28, 2005 that CHAR_BIT be used here and
// throughout rather than assuming bytes were 8 bits long. Angus recommended
// the more portable versions above, involving casting on March 4, 2006.
// Rohit Garg suggested the version for non-negative integers on September 12, 2009. 
grokus
  • 18,046
  • 9
  • 29
  • 35
4
#include<stdio.h>

void main()
{
    int n;  // assuming int to be 32 bit long

    //shift it right 31 times so that MSB comes to LSB's position
    //and then and it with 0x1
    if ((n>>31) & 0x1 == 1) {
        printf("negative number\n");
    } else {
        printf("positive number\n");
    }

    getch();
}
Maerlyn
  • 33,687
  • 18
  • 94
  • 85
3

It is quite simple

It can be easily done by

return ((!!x) | (x >> 31));

it returns

  • 1 for a positive number,
  • -1 for a negative, and
  • 0 for zero
user207421
  • 305,947
  • 44
  • 307
  • 483
noufal
  • 940
  • 3
  • 15
  • 32
  • 3
    Assuming 32 bit integers :) – AndyG Jan 23 '14 at 00:04
  • 1
    @AndyG `return ((!!x) | (x >> (8 * sizeof (int) -1)));`would be a better way I think. – noufal Jan 23 '14 at 06:41
  • When I evaluated this expression, for negative values of x,it returned 1 instead of -1.Can you please correct my mistake: if x=-ve,then, (!x)=0 =>(!!x)=1 ; x>>31 =1 ; Therefore ((!!x) | (x >> 31)) = (1)|(1) = (1) – piyukr Aug 19 '14 at 11:23
  • 1
    Right shifting negative numbers has implementation defined behavior. – chqrlie Aug 25 '20 at 13:00
3

Signed integers and floating points normally use the most significant bit for storing the sign so if you know the size you could extract the info from the most significant bit.

There is generally little benefit in doing this this since some sort of comparison will need to be made to use this information and it is just as easy for a processor to tests whether something is negative as it is to test whether it is not zero. If fact on ARM processors, checking the most significant bit will be normally MORE expensive than checking whether it is negative up front.

doron
  • 27,972
  • 12
  • 65
  • 103
2
// if (x < 0) return -1
// else if (x == 0) return 0
// else return 1
int sign(int x) {
  // x_is_not_zero = 0 if x is 0 else x_is_not_zero = 1
  int x_is_not_zero = (( x | (~x + 1)) >> 31) & 0x1;
  return (x & 0x01 << 31) >> 31 | x_is_not_zero; // for minux x, don't care the last operand 
}

Here's exactly what you waht!

Qylin
  • 1,501
  • 1
  • 16
  • 26
2

This can not be done in a portable way with bit operations in C. The representations for signed integer types that the standard allows can be much weirder than you might suspect. In particular the value with sign bit on and otherwise zero need not be a permissible value for the signed type nor the unsigned type, but a so-called trap representation for both types.

All computations with bit operators that you can thus do might have a result that leads to undefined behavior.


In any case as some of the other answers suggest, this is not really necessary and comparison with < or > should suffice in any practical context, is more efficient, easier to read... so just do it that way.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
2

Here is an update related to C++11 for this old question. It is also worth considering std::signbit.

On Compiler Explorer using gcc 7.3 64bit with -O3 optimization, this code

bool s1(double d)
{
    return d < 0.0;
}

generates

s1(double):
  pxor xmm1, xmm1
  ucomisd xmm1, xmm0
  seta al
  ret

And this code

bool s2(double d)
{
    return std::signbit(d);
}

generates

s2(double):
  movmskpd eax, xmm0
  and eax, 1
  ret

You would need to profile to ensure that there is any speed difference, but the signbit version does use 1 less opcode.

Paul Floyd
  • 5,530
  • 5
  • 29
  • 43
  • Yup, `movmskpd` is efficient on most CPUs (https://agner.org/optimize/). If you just want the sign bit, that's a good choice, especially if the compiler knows it has a local `double` already zero-extended in an XMM register (e.g. after loading with `movsd`), so it can skip the AND if it spots that optimizations. – Peter Cordes Jan 04 '19 at 02:33
  • 1
    Note that these functions are different for `-0.0` and NaN: signbit always gives you the sign bit, but `d < 0.0` is false for `-0.0` (it's considered equal, not less), and for `-NaN` (because the comparison is unordered). – Peter Cordes Jan 04 '19 at 02:34
1

When you're sure about the size of an integer (assuming 16-bit int):

bool is_negative = (unsigned) signed_int_value >> 15;

When you are unsure of the size of integers:

bool is_negative = (unsigned) signed_int_value >> (sizeof(int)*8)-1; //where 8 is bits

The unsigned keyword is optional.

Ino
  • 479
  • 4
  • 5
1
if( (num>>sizeof(int)*8 - 1) == 0 )
    // number is positive
else
   // number is negative

If value is 0 then number is positive else negative

Nazar554
  • 4,105
  • 3
  • 27
  • 38
shashank
  • 11
  • 1
  • Right shifting negative numbers has implementation defined behavior. Also the OP specified *without using any conditional statements/operators like if/ternary* – chqrlie Aug 25 '20 at 12:59
1

A simpler way to find out if a number is positive or negative: Let the number be x check if [x * (-1)] > x. if true x is negative else positive.

akundu
  • 13
  • 3
0

You can differentiate between negative/non-negative by looking at the most significant bit. In all representations for signed integers, that bit will be set to 1 if the number is negative.

There is no test to differentiate between zero and positive, except for a direct test against 0.

To test for negative, you could use

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1)))
Bart van Ingen Schenau
  • 15,488
  • 4
  • 32
  • 41
  • The size and the width of an integer type are not strictly related in the sense that you are suggesting. Second the most significant bit of the unsigned type is not necessarily the sign bit: the width of the corresponding signed type might be smaller, or it might even be one more than that of the unsigned type. – Jens Gustedt Sep 23 '10 at 15:04
  • @Jens: Pedantically speaking, you are right and is it impossible to determine which bit contains the sign. But can you name a platform in existence where this code does not work? – Bart van Ingen Schenau Sep 23 '10 at 15:21
  • They are rare, I admit, but exist. Unfortunately in German, but you might get the idea: http://www.schellong.de/c_padding_bits.htm. Also in this discussion there is an interesting example: http://www.rhinocerus.net/forum/lang-c/2007-padding-bits.html – Jens Gustedt Sep 23 '10 at 15:55
0
#include<stdio.h>
int checksign(int n)
{
    return (n >= 0 && (n & (1<<32-1)) >=0); 
}
void main()
{
  int num = 11;
  if(checksign(num))
    {
      printf("Unsigned number"); 
    }
  else
    {
      printf("signed Number");
    }
}
jcoppens
  • 5,306
  • 6
  • 27
  • 47
  • 1
    `1<<32-1` has undefined behavior if type `int` has 32 bits or less. – chqrlie May 22 '21 at 17:25
  • @chqrlie "1<<32-1 has undefined behavior if type int has 32 bits or less." By the way, there's an article from 3 days ago that critiques the standard precisely on that point: https://www.yodaiken.com/2021/05/19/undefined-behavior-in-c-is-a-reading-error/ – kelvin May 22 '21 at 17:52
  • 1
    @kelvin: I fully agree with the blog contents. UB is a plague, but taking advantage of it for counterintuitive optimisations is perverse. – chqrlie May 22 '21 at 19:12
0

Suppose your number is a=10 (positive). If you shift a a times it will give zero.

i.e:

10>>10 == 0

So you can check if the number is positive, but in case a=-10 (negative):

-10>>-10 == -1

So you can combine those in an if:

if(!(a>>a))
   print number is positive
else 
   print no. is negative 
sth
  • 222,467
  • 53
  • 283
  • 367
0

Without if:

string pole[2] = {"+", "-"};
long long x;
while (true){
    cin >> x;
    cout << pole[x/-((x*(-1))-1)] << "\n\n";
} 

(not working for 0)

-1
if(n & (1<<31)) 
{
  printf("Negative number");
}
else{
  printf("positive number");
 }

It check the first bit which is most significant bit of the n number and then & operation is work on it if the value is 1 which is true then the number is negative and it not then it is positive number

  • There is a missing `)` on the first line and `(1<<31)` has undefined behavior if `int` has 32 bits. You could write `if (n & (1U << 31))` or more precisely `if (n & (1U << (CHAR_BIT * sizeof(int) - 1)))` which would be OK for 2s complement systems. – chqrlie Aug 25 '20 at 12:56
  • Also the OP specified *without using any conditional statements/operators like if/ternary* – chqrlie Aug 25 '20 at 12:56