检查给定整数是否为负的一种方法可能是:(使用位操作)
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?
答案 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类型。