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

发布于 2024-09-24 19:14:38 字数 118 浏览 2 评论 0原文

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

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

趴在窗边数星星i 2024-10-01 19:14:38

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

当然:

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

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

Of course:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
混浊又暗下来 2024-10-01 19:14:38

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

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

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

添加:

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

int isNegative = (x & 0x80000000);

稍后你可以使用 if (isNegative) 来测试它。

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

这样的小城市 2024-10-01 19:14:38

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

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

参考:http://en.cppreference.com/w/cpp/numeric/math /符号位

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

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

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

两相知 2024-10-01 19:14:38

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. 

There is a detailed discussion on the 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. 
情绪少女 2024-10-01 19:14:38
#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();
}
#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();
}
左耳近心 2024-10-01 19:14:38

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

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

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.

耳钉梦 2024-10-01 19:14:38

它非常简单,

可以很容易地完成,它

return ((!!x) | (x >> 31));

返回

  • 1 表示正数,
  • -1 表示负数,
  • 0 表示零

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
习惯成性 2024-10-01 19:14:38

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

因此,您可以使用位运算符进行的所有计算都可能会产生导致未定义行为的结果。


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

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.

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.

氛圍 2024-10-01 19:14:38
// 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 
}

这正是您想要的!

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

相对绾红妆 2024-10-01 19:14:38

这是针对这个老问题的与 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

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

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

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

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.

一指流沙 2024-10-01 19:14:38

当您确定整数的大小时(假设为 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 关键字是可选的。

When you're sure about the size of an integer (assuming 16-bit int):

bool is_negative = (unsigned) signed_int_value >> 15;

When you are unsure of the size of integers:

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

The unsigned keyword is optional.

看海 2024-10-01 19:14:38
if( (num>>sizeof(int)*8 - 1) == 0 )
    // number is positive
else
   // number is negative

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

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

If value is 0 then number is positive else negative

中二柚 2024-10-01 19:14:38

判断数字是正数还是负数的更简单方法:
设数字为x
检查是否 [x * (-1)] > x。如果 true x 为负值,则为正值。

A simpler way to find out if a number is positive or negative:
Let the number be x
check if [x * (-1)] > x. if true x is negative else positive.

埋葬我深情 2024-10-01 19:14:38

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

除了针对 0 的直接测试之外,没有任何测试可以区分零和正数。

要测试负数,您可以使用

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

You can differentiate between negative/non-negative by looking at the most significant bit.
In all representations for signed integers, that bit will be set to 1 if the number is negative.

There is no test to differentiate between zero and positive, except for a direct test against 0.

To test for negative, you could use

#define IS_NEGATIVE(x) ((x) & (1U << ((sizeof(x)*CHAR_BIT)-1)))
以可爱出名 2024-10-01 19:14:38

假设您的数字是 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 

Suppose your number is a=10 (positive). If you shift a a times it will give zero.

i.e:

10>>10 == 0

So you can check if the number is positive, but in case a=-10 (negative):

-10>>-10 == -1

So you can combine those in an if:

if(!(a>>a))
   print number is positive
else 
   print no. is negative 
千纸鹤带着心事 2024-10-01 19:14:38
#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");
    }
}
#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");
    }
}
转身泪倾城 2024-10-01 19:14:38

没有 if:

string pole[2] = {"+", "-"};
long long x;
while (true){
    cin >> x;
    cout << pole[x/-((x*(-1))-1)] << "\n\n";
} 

(不适用于 0)

Without if:

string pole[2] = {"+", "-"};
long long x;
while (true){
    cin >> x;
    cout << pole[x/-((x*(-1))-1)] << "\n\n";
} 

(not working for 0)

横笛休吹塞上声 2024-10-01 19:14:38
if(n & (1<<31)) 
{
  printf("Negative number");
}
else{
  printf("positive number");
 }

它检查第 n 个数字的最高有效位,然后 &如果值为 1(为 true 则该数字为负数),则对其进行操作,否则为正数

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

It check the first bit which is most significant bit of the n number and then & operation is work on it if the value is 1 which is true then the number is negative and it not then it is positive number

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文