web-dev-qa-db-ja.com

ビット演算子を使用して数値が正か負かを確認する

ビットごとの演算子を使用して、数値が奇数か偶数かを確認できます。 if/ternaryなどの条件ステートメント/演算子を使用せずに、数値が正/ゼロ/負であるかどうかを確認できますか?.

同じことをビット演算子とCまたはC++のトリックを使用して実行できますか?

30
Anirudhh Er

If/ternaryなどの条件ステートメント/演算子を使用せずに、数値が正/ゼロ/負であるかどうかを確認できますか?.

もちろん:

bool is_positive = number > 0;
bool is_negative = number < 0;
bool is_zero = number == 0;
27
Konrad Rudolph

上位ビットが符号付き整数(バイト、longなど、ただし浮動小数点数ではない)に設定されている場合、その数値は負です。

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

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

追加:

あなたは、条件を使用したくないと言った。私はあなたがこれを行うことができると思います:

_int isNegative = (x & 0x80000000);
_

しばらくしてから、if (isNegative)でテストできます。

16
Jim Mischel

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. 
11
grokus

または、 signbit() を使用すると、作業が完了します。

私は、フードの下で、math.h実装は、効率的なビット単位のチェックです(元の目標を解決する可能性があります)。

リファレンス: http://en.cppreference.com/w/cpp/numeric/math/signbit

11
William Denniss
#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();
}
4

符号付き整数と浮動小数点は通常、符号の格納に最上位ビットを使用するため、サイズがわかっている場合は、最上位ビットから情報を抽出できます。

この情報を使用するには何らかの比較を行う必要があり、プロセッサがゼロでないかどうかをテストするのと同じくらい簡単に何かがネガティブかどうかをテストする必要があるため、これを行うことには一般にほとんど利点がありません。実際にARMプロセッサである場合、最上位ビットをチェックすることは、前もって負であるかどうかをチェックするよりも通常高価です。

3
doron

とても簡単です

それは簡単にできます

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

それは戻ります

  • 正数の場合は1、
  • -1、負の場合、および
  • ゼロの場合は0
3
noufal
// 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 
}

まさにあなたが欲しいものです!

2
Qylin

この古い質問に対するC++ 11に関連する更新を以下に示します。 std :: signbit も検討する価値があります。

-O3最適化でgcc 7.3 64ビットを使用するコンパイラエクスプローラで、このコード

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つ少ないオペコードを使用します。

2
Paul Floyd

数値が正か負かを調べる簡単な方法:数値をxにして、[x *(-1)]> xかどうかを確認します。真のxが負の場合、正の場合。

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

値が0の場合、数値は正、そうでない場合は負

1
shashank

これは、Cのビット操作を使用して移植可能な方法で実行することはできません。標準で許可されている符号付き整数型の表現は、予想よりもはるかに奇妙です。特に、符号ビットがオンで、そうでなければゼロの値は、符号付きタイプまたは符号なしタイプの許容値である必要はなく、両方のタイプのいわゆるトラップ表現である必要があります。

したがって、ビット演算子を使用したすべての計算では、未定義の動作につながる結果が生じる可能性があります。


いずれにせよ、他の回答のいくつかが示唆しているように、これは実際には必要ではなく、<または>との比較で実用的な状況で十分であり、より効率的で読みやすい...そのように。

1
Jens Gustedt

最上位ビットを見ることで、ネガティブ/非ネガティブを区別できます。符号付き整数のすべての表現では、数値が負の場合、そのビットは1に設定されます。

0に対する直接テストを除き、ゼロとポジティブを区別するテストはありません。

陰性をテストするには、使用できます

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

あなたの番号がa=10(正)。 aa回シフトすると、ゼロになります。

すなわち:

10>>10 == 0

そのため、数値が正かどうかを確認できますが、a=-10(負):

-10>>-10 == -1

したがって、これらをifで組み合わせることができます。

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

整数のサイズについて確信がある場合(16ビット整数と仮定):

bool is_negative = (unsigned) signed_int_value >> 15;

整数のサイズがわからない場合:

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

unsignedキーワードはオプションです。

0
Ino