使用按位运算符检查数字是正数还是负数

时间:2010-09-23 14:06:22

标签: c++ c algorithm bit-manipulation

我可以使用按位运算符检查数字是否为奇数/偶数。我可以在不使用任何条件语句/运算符(如if / ternary等)的情况下检查数字是正数还是零/负数。

可以使用按位运算符和C或C ++中的一些技巧来完成相同的操作吗?

17 个答案:

答案 0 :(得分:27)

  

我可以在不使用任何条件语句/运算符(如if / ternary等)的情况下检查数字是正数还是零/负数。

当然:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;

答案 1 :(得分:16)

如果高位设置在有符号整数(字节,长整数等,但不是浮点数)上,则该数字为负数。

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

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

增加:

你说你不想使用任何条件。我想你可以这样做:

int isNegative = (x & 0x80000000);

稍后您可以使用if (isNegative)进行测试。

答案 2 :(得分:11)

有关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. 

答案 3 :(得分:11)

或者,您可以使用signbit()并为您完成工作。

我假设在幕后,math.h实现是一种有效的按位检查(可能解决您的原始目标)。

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

答案 4 :(得分: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();
}

答案 5 :(得分:3)

有符号整数和浮点通常使用最高位来存储符号,因此如果您知道大小,则可以从最高位提取信息。

这样做通常没什么好处,因为需要进行某种比较才能使用这些信息,处理器测试是否为负是非常容易,因为测试是否不是零。如果在ARM处理器上存在事实,那么检查最重要的位通常比检查它是否为正面更为昂贵。

答案 6 :(得分:3)

很简单

可以通过

轻松完成
return ((!!x) | (x >> 31));

它返回

  • 1表示正数,
  • -1表示否定,
  • 0表示零

答案 7 :(得分: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 
}

这正是你所喜欢的!

答案 8 :(得分:2)

这是针对这个老问题的与C ++ 11相关的更新。值得考虑std::signbit

在编译器资源管理器上使用gcc 7.3 64位和-O3优化,此代码

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

产生

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

这段代码

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

产生

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

您需要进行配置以确保存在任何速度差异,但是signbit版本确实使用了少1个操作码。

答案 9 :(得分:1)

这不能以C语言中的位操作的可移植方式完成。标准允许的有符号整数类型的表示可能比您可能怀疑的更奇怪。特别是符号位开启且否则为零的值不必是有符号类型和无符号类型的允许值,而是两种类型的所谓陷阱表示。

所有使用位操作符的计算都可能导致未定义的行为。


在任何情况下,正如其他一些答案所暗示的那样,这并不是必需的,与<>的比较在任何实际情况下都应该足够,更有效,更容易阅读......所以就这样做吧。

答案 10 :(得分:1)

if( (num>>sizeof(int)*8 - 1) == 0 )
    // number is positive
else
   // number is negative

如果值为0则数字为正,否则为负数

答案 11 :(得分:1)

查明数字是正数还是负数的更简单方法: 设数为x 检查是否[x *( - 1)]&gt; X。如果是真的x是负的,那么正面。

答案 12 :(得分:0)

假设您的号码为a=10(正数)。如果您将a a次移动,则会给出零。

即:

10>>10 == 0

因此,您可以检查数字是否为正,但如果a=-10(否定):

-10>>-10 == -1

因此,您可以将这些内容合并到if

if(!(a>>a))
   print number is positive
else 
   print no. is negative 

答案 13 :(得分:0)

当你确定整数的大小时(假设是16位int):

bool is_negative = (unsigned) signed_int_value >> 15;

当你不确定整数的大小时:

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

unsigned关键字是可选的。

答案 14 :(得分:0)

您可以通过查看最重要的位来区分负面/非负面。 在有符号整数的所有表示中,如果数字为负,则该位将设置为1。

除了针对0的直接测试外,没有测试来区分零和正。

要测试否定,您可以使用

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1)))

答案 15 :(得分: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");
    }
}

答案 16 :(得分:-1)

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

检查第一个是n个数字的最高有效位,然后对&进行运算,如果值为1,则为true,则该数字为负,而不是正数。

相关问题