web-dev-qa-db-ja.com

「==」をビット演算子で置き換える

ビットごとの演算子(|、&、〜、^、>>、<<)と、+、-、!などの他の基本的な演算子のみを使用して、以下の「==」を置き換えることはできますか?

int equal(int x, int y) {
    return x == y;
}
25
not_l33t

2つの数値に違いがない場合、それらは等しくなります。

int equal(int x, int y){
   return !(x-y);
}
23
sth

XORNOT EQUALSとまったく同じであり、XNOREQUALSとまったく同じであることに注意してください。したがって、次のようにすると、正確に必要なものが得られます。

return !(x ^ y);

C !演算子は実際には!= 0の省略形なので、これを使用することは不正行為に非常に近いようです:)

これは、ビット単位の演算を使用した私の考えです。32ビットの2の補数マシンで算術右シフトを想定しています(厳密には、Cの算術右シフトは未定義ですが、2の補数マシンでこれまでに見たすべてのCコンパイラはこれを正しくサポートしています)。

int t = (x - y) | (y - x); // <0 iff x != y, 0 otherwise
t >>= 31; // -1 iff x != y, 0 otherwise
return 1 + t; // 0 iff x != y, 1 otherwise

とはいえ、実際のコンパイラにはこの問題はありません。実際のハードウェアは、比較を直接サポートしています。詳細はアーキテクチャによって異なりますが、2つの基本モデルがあります。

  1. 算術演算で返される条件コード(例:x86およびARMこれを行います)。この場合、通常、2つの値を減算する「比較」命令があり、整数レジスタに書き戻しませんが、結果に基づいて条件コード/フラグを設定します。
  2. より多くのRISCのようなプラットフォームには、通常、比較を行い、結果に基づいて分岐する直接の「等しい場合の分岐」および「より小さい場合の分岐」オペランドがあります。基本的にはCコードと同等です

    if (a == b) goto label;
    

    または

    if (a < b) goto label;
    

    すべて1つの機械語命令で。

16
Fabian Giesen

この例は減算と同じですが、一部のアーキテクチャがレジスタ比較をどのように行うかについてより明確です(ARMなど)。

return !(1 + ~x + y);

1は、ALUへのキャリービット入力を示します。 1つの数値xはビット単位で補われます。補数を取り、1を加えると、数値の2の補数が生成されます(x-x)、それから他の数値に加算して、等しいかどうかを判断するための差を取得します。

したがって、両方の数値が等しい場合、-x + x => 0

(レジスタレベルでは!演算子は実行されず、条件コードまたはフラグレジスタの「ゼロビット」をテストするだけです。これは、レジスター操作がゼロの結果を生成する場合に設定され、それ以外の場合はクリアされます。)

3
indiv

XORは(!=)と同じであるため、(x ^ y)は等しい値に対してのみ0を返します。賢明であり、ビットごとの演算子を使用し、 。

int notEqual(int x, int y){
        return (x ^ y);
}
1
Saurabh Sachdeo

これについての私の見解

int equal(int x, int y){
   if((x & ~y) == 0)
       return 1;
   else
       return 0; 
}

説明:x == yの場合、x & ~y0に評価されて1を返し、それ以外の場合はx!=yとして0を返します。

Edit1: The above is equivalent to 

int equal(int x, int y){
    return !(x & ~y) ; // returns 1 if equal , 0 otherwise. 
}

上記のコードは、最上位ビットが1になる特定の場合に失敗します。解決策は1を追加することです。つまり、正しい答えは

return !(x & (~y +1) );
0
Eternal Learner