Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detection of negative integers using bit operations

Tags:

c++

c

binary

One approach to check if a given integer is negative or not, could be this: (using bit operations)

int num_bits = sizeof(int) * 8; //assuming 8 bits per byte!
int sign_bit = given_int & (1 << (num_bits-1)); //sign_bit is either 1 or 0
if ( sign_bit )
{
     cout << "given integer is negative"<<endl;
}
else
{
     cout << "given integer is positive"<<endl;
}

The problem with this solution is that number of bits per byte couldn't be 8, it could be 9,10, 11 even 16 or 40 bits per byte. Byte doesn't necessarily mean 8 bits! Anyway, this problem can be easily fixed by writing,

//CHAR_BIT is defined in limits.h
int num_bits = sizeof(int) * CHAR_BIT; //no assumption. 

It seems fine now. But is it really? Is this Standard conformant? What if the negative integer is not represented as 2's complement? What if it's representation in a binary numeration system that doesn't necessitate only negative integers to have 1 in it's most significant bit?

Can we write such code that will be both portable and standard conformant?


Related topics:
Size of Primitive data types
Why is a boolean 1 byte and not 1 bit of size?

like image 806
Nawaz Avatar asked Jan 15 '11 06:01

Nawaz


People also ask

How do you check if a number is negative with bits?

For signed binary numbers the most significant bit (MSB) is used as the sign bit. If the sign bit is “0”, this means the number is positive in value. If the sign bit is “1”, then the number is negative in value.

How Bitwise operations are applied on negative numbers?

The approach is quite simple: Use bitwise not to transform any negative integer into a non-negative integer, apply one of the functions 0–7, and then possibly apply bitwise not again to obtain the result.

Why is Bitwise not negative?

Whether an integer is positive or negative (the sign of the integer) is stored in a dedicated bit, the sign bit. The bitwise NOT affects this bit, too, so any positive number becomes a negative number and vice versa.


2 Answers

NOTE: C and C++ are different languages. Their respective standards have evolved somewhat independently and they have differing formal restrictions on numeric representation.


Can we write such code that will be both portable and standard conformant?

Assuming that you require a general method of identifying and interpreting a sign bit, I think the answer to your question is No.

Regarding C++: I don't think that the standard has an explicit requirement for the existence of a sign bit. Even if every implementation uses a sign bit, there is no guarantee that it is the first (high-order) bit as your code assumes. Also, the bit could have the opposite interpretation from what you are assuming (a "1" value for the sign bit could mean that the number is positive).

Regarding C99: The language does require a sign bit and requires that sign=1 indicates a negative number (although it might be "negative zero"). However, the language standard does not give you a general way of determining where the sign bit is.

The following code attempts to create a "sign_mask" in a generic way, but it is not absolutely guaranteed to work in C99 or C++. Reasons for failure include those mentioned above, but most interestingly, it could invoke a "trap representation" (such as a parity bit error)...

#ifdef __cplusplus
   #define INT_MAX std::numeric_limits<int>::max()
   #define UINT_MAX std::numeric_limits<unsigned int>::max() 
#endif

// assumes sign bit becomes high-order bit of unsigned
   int sign_mask = INT_MAX ^ UINT_MAX; 

// fallback in case unsigned type doesn't take advantage of the sign-bit
// This might invoke a "trap representation" on some platforms
   if (sign_mask==0) sign_mask = ~INT_MAX;

This Wikipedia article discusses some different ways that signed numbers can be represented in binary: Signed number representations

Here's an informative post about signed numbers in the C99 standard.

like image 63
8 revs Avatar answered Oct 23 '22 07:10

8 revs


Cast the integer to the corresponding unsigned type and then you don't have to worry about what signed representation is in use. The only remaining issue is that there may be padding bits. Here's a solution with no bit shifting and thus no dependence on width in bits matching the size in bits:

#define IS_NEG(x) ((unsigned_type)x & (unsigned_type)-1-(unsigned_type)-1/2)
like image 2
R.. GitHub STOP HELPING ICE Avatar answered Oct 23 '22 07:10

R.. GitHub STOP HELPING ICE