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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3779202/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:42:21  来源:igfitidea点击:

Checking whether a number is positive or negative using bitwise operators

c++calgorithmbit-manipulation

提问by Anirudhh Er

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.

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

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

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

回答by Konrad Rudolph

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

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

Of course:

当然:

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

回答by Jim Mischel

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).

稍后您可以使用if (isNegative).

回答by grokus

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

Bit Twiddling Hacks 页面上有详细的讨论。

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. 

回答by William Denniss

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

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

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

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

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

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

回答by Nitesh Pratap Singh

#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();
}

回答by doron

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.

这样做通常没有什么好处,因为需要进行某种比较才能使用此信息,并且处理器测试某些内容是否为负与测试它是否不为零一样容易。如果事实上在 ARM 处理器上,检查最高有效位通常比预先检查它是否为负值更昂贵。

回答by noufal

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
  • 1 为正数,
  • -1 为负,和
  • 0 表示零

回答by Paul Floyd

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

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

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

在使用带有 -O3 优化的 gcc 7.3 64bit 的编译器资源管理器上,此代码

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.

您需要进行分析以确保存在任何速度差异,但符号位版本确实使用少 1 个操作码。

回答by Qylin

// 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!

这正是你想要的!

回答by Jens Gustedt

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.

这不能通过 C 中的位操作以可移植的方式完成。标准允许的有符号整数类型的表示可能比您想象的要奇怪得多。特别是,符号位为 on 否则为零的值不需要是有符号类型或无符号类型的允许值,而是两种类型的所谓陷阱表示。

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.

无论如何,正如其他一些答案所暗示的那样,这并不是真正必要的,并且在任何实际情况下与<>应该进行比较就足够了,效率更高,更易于阅读......所以就这样做吧。