使用位操作检测负整数

时间:2011-01-15 06:23:46

标签: c++ c binary

检查给定整数是否为负的一种方法可能是:(使用位操作

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;
}

这个解决方案的问题是每个字节的比特数不能是8,它可能是每个字节9,10,11甚至16或40比特。字节不一定意味着8位!无论如何,这个问题可以通过写作轻松解决,

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

现在看起来很好。但它真的吗?这个标准符合吗?如果负整数不表示为2的补码怎么办?如果它在二进制数字系统中的表示需要负整数在其中最重要的位有1?

我们可以编写既可移植又符合标准的代码?


相关主题:
Size of Primitive data types
Why is a boolean 1 byte and not 1 bit of size?

4 个答案:

答案 0 :(得分:4)

注意:C和C ++是不同的语言。他们各自的标准在某种程度上独立发展,他们对数字表示有不同的正式限制。


  

我们可以编写既可移植又符合标准的代码?

假设您需要一种识别和解释符号位的通用方法,我认为您的问题的答案是否定。

关于C ++:我不认为该标准明确要求存在符号位。即使每个实现都使用符号位,也不能保证它是代码假设的第一个(高位)位。此外,该位可能与您所假设的具有相反的解释(符号位的“1”值可能意味着该数字为正)。

关于C99:语言确实需要符号位,并且要求sign = 1表示负数(尽管它可能是“负零”)。但是,语言标准没有为您提供确定符号位的一般方法。

以下代码尝试以通用方式创建“sign_mask”,但不能绝对保证在C99或C ++中工作。失败的原因包括上面提到的那些,但最有趣的是,它可以调用“陷阱表示”(例如奇偶校验位错误)......

#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;

这篇维基百科文章讨论了签名数字可用二进制表示的一些不同方式:Signed number representations

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

答案 1 :(得分:2)

将整数转换为相应的无符号类型,然后您不必担心正在使用的已签名表示。唯一剩下的问题是可能存在填充位。这是一个没有位移的解决方案,因此在位中匹配 size 的位中不依赖于 width

#define IS_NEG(x) ((unsigned_type)x & (unsigned_type)-1-(unsigned_type)-1/2)

答案 2 :(得分:0)

使用循环移位进行比特换行等操作,这样你就可以在比特串开头的拇指下找到最后一点,然后bool neg = n & 1;它或者什么。这里有一些用于位换行的代码:

template <typename T>
inline T rotate_left(T val, unsigned char shift=1)
{
    static const bits = sizeof(T) * CHAR_BIT;
    return (val >> (bits-shift)) | (val << shift);
}

template <typename T>
inline T rotate_right(T val, unsigned char shift=1)
{
    static const bits = sizeof(T) * CHAR_BIT;
    return (val << (bits-shift)) | (val >> shift);
}

// And now for some platform-dependant specializations...

#include <intrin.h>

template<>
inline unsigned char rotate_left(unsigned char val, unsigned char shift=1)
{
    return _rotl8(val, shift);
}

template<>
inline unsigned char rotate_right(unsigned char val, unsigned char shift=1)
{
    return _rotr8(val, shift);
}

template<>
inline unsigned int rotate_left(unsigned int val, unsigned char shift=1)
{
    return _rotl(val, shift);
}

template<>
inline unsigned int rotate_right(unsigned int val, unsigned char shift=1)
{
    return _rotr(val, shift);
}

template<>
inline unsigned long long rotate_left(unsigned long long val, unsigned char shift=1)
{
    return _rotl64(val, shift);
}

template<>
inline unsigned long long rotate_right(unsigned long long val, unsigned char shift=1)
{
    return _rotr64(val, shift);
}

答案 3 :(得分:0)

扩展R.s方法:

template <typename T> is_negative(T v) {
    boost::make_unsigned<T>::type u(v);
    return (u & (1 << std::numeric_limits<T>::digits - 1));
}

如果你不喜欢使用boost(make_unsigned在type_traits中),只需使用你平台上最大的unsigned int类型。