2 つの整数の符号が同じかどうかを確認する最も簡単な方法はどれですか? これを行うための短いビット単位のトリックはありますか?
19 に答える
どうしたの
return ((x<0) == (y<0));
?
これは、整数サイズに依存しない、またはオーバーフローの問題を抱えていない C/C++ で動作するバージョンです (つまり、x*y>=0 は動作しません)。
bool SameSign(int x, int y)
{
return (x >= 0) ^ (y < 0);
}
もちろん、こっそりとテンプレート化することもできます。
template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
return (x >= 0) ^ (y < 0);
}
注: 排他的 OR を使用しているため、符号が同じ場合は LHS と RHS が異なる必要があるため、ゼロに対する異なるチェックが行われます。
(a ^ b) >= 0
符号が同じ場合は 1、そうでない場合は 0 と評価されます。
整数の符号を決定するためのビット単位のトリックには注意が必要です。その場合、これらの数値が内部でどのように表現されるかについて仮定する必要があるからです。
ほぼ 100% の場合、整数は2 の補数として格納されますが、特定の格納形式を保証するデータ型を使用していない限り、システムの内部について仮定することはお勧めできません。
2 の補数では、整数の最後の (一番左の) ビットをチェックして負かどうかを判断できるため、これら 2 つのビットだけを比較できます。これは、0 が正の数と同じ符号を持つことを意味しますが、これはほとんどの言語で実装されている符号関数と矛盾しています。
個人的には、選択した言語の符号関数を使用したいと思います。このような計算でパフォーマンスの問題が発生する可能性はほとんどありません。
32 ビット整数を想定すると、次のようになります。
bool same = ((x ^ y) >> 31) != 1;
もう少し簡潔に:
bool same = !((x ^ y) >> 31);
(整数 1 * 整数 2) > 0
2 つの整数が符号を共有している場合、乗算の結果は常に正になるためです。
何があっても同じ符号として 0 を扱いたい場合は、 >= 0 にすることもできます。
「ビットごとのトリック」と「最も単純な」を同義語と見なすかどうかはよくわかりません。符号付きの 32 ビット整数を想定している回答がたくさんあります (ただし、符号なしを求めるのはばかげています) 。それらが浮動小数点値に適用されるかどうかはわかりません。
「最も簡単な」チェックは、両方の値が 0 とどのように比較されるかを比較することです。型を比較できると仮定すると、これはかなり一般的です。
bool compare(T left, T right)
{
return (left < 0) == (right < 0);
}
符号が反対の場合は、false になります。符号が同じであれば、真になります。
2の補数演算を仮定すると(http://en.wikipedia.org/wiki/Two_complement):
inline bool same_sign(int x, int y) {
return (x^y) >= 0;
}
これは、最適化された最新のプロセッサでは、わずか2命令、1ns未満で済みます。
2の補数の算術を仮定しない:
inline bool same_sign(int x, int y) {
return (x<0) == (y<0);
}
これには、1つまたは2つの追加の指示が必要で、少し時間がかかる場合があります。
乗算はオーバーフローに対して脆弱であるため、乗算を使用することはお勧めできません。
(x * y) > 0 の場合...
非ゼロなどを想定しています。
技術的な注意点として、最新のアーキテクチャであっても、ビット操作のソリューションは乗算よりもはるかに効率的です。節約できるのは約 3 サイクルだけですが、「ペニー節約」について彼らが何と言っているか知っています...
頭のてっぺんから...
int mask = 1 << 31;
(a & mask) ^ (b & mask) < 0;
(a*b < 0) 符号が異なる場合、そうでなければ符号は同じ (または a または b がゼロ)
ブランチレス C バージョン:
int sameSign(int a, int b) {
return ~(a^b) & (1<<(sizeof(int)*8-1));
}
整数型の C++ テンプレート:
template <typename T> T sameSign(T a, T b) {
return ~(a^b) & (1<<(sizeof(T)*8-1));
}
2 の補数演算による任意のサイズの int の場合:
#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
// signs are the same
32ビットを想定
if(((x^y) & 0x80000000) == 0)
...オーバーフローのため、答えif(x*y>0)
は悪いです
次のようにstd::signbitを使用するより良い方法:
std::signbit(firstNumber) == std::signbit(secondNumber);
他の基本型 ( 、 など) もサポートしてdouble
いfloat
ますchar
。
int same_sign = !( (x >> 31) ^ (y >> 31) );
if ( same_sign ) ... else ...
大学時代を思い出すと、ほとんどの機械表現では、整数の左端のビットは、負の場合は 1 であり、正の場合は 0 ではないでしょうか?
ただし、これはかなりマシンに依存していると思います。