C言語でビット演算を利用して絶対値を返す関数の仕組みが理解できない


C言語で、ビット演算を使い絶対値を返す関数について調べていた所ネットで以下の様に作成できることがわかりました。

[code]

    int myabs(int b) {
        return (b ^ (b >> 31)) - (b >> 31);
    }
    
[/code]

確かに実際に↑の関数を書いたコードで試してみると絶対値が求められるのですが仕組みがどうも分かりません。

例えば `b`が `0x00000001` の場合,

`(b >> 31)` = `0x00000000`,  
`(b ^ (b >> 31))` = `0xFFFFFFFE`,  
`(b ^ (b >> 31)) - (b >> 31)` = `0xFFFFFFFE` となりませんか？




b が 0x00000001 の場合、

[code]

    (b ^ (b >> 31)) = 0x00000001
    
[/code]

ですね。

* * *

以下、`myabs()` の説明です。

絶対値を求めるなら、

  * 元の数値が 0以上ならそのまま
  * 元の数値が負数なら符号を反転

とすれば良いわけです。ここに、2の補数の

  * 全てのビットを反転して +1 すると値の符号が反転する。
  * 最上位ビットは符号である。

という特徴を活かします。

`b >> 31` は、最上位ビットで他の31ビットを塗りつぶします。  
つまり、

  * `b` が 0 以上なら 0
  * `b` が負数なら -1 (全てのビットが 1)

となります。

従って `(b ^ (b >> 31))` は

  * `b` が 0 以上なら何も起きない (`b >> 31` が 0 だから)
  * `b` が負数なら `b` のビットが全て反転する (`b >> 31` は全てのビットが 1 だから)

ということになります。  
また `- (b >> 31)` の部分ですが、これは

  * `b` が 0 以上なら 0 (`b >> 31` が 0 だから)
  * `b` が負数なら +1 (`b >> 31` が -1 だから)

となります。

以上の処理により、

  * `b` が 0 以上なら何もせず `b` のまま
  * `b` が負数ならビットを反転して +1 する (つまり符号を反転する)

という処理が実現できていることになり、絶対値が求まります。




b が 0x00000001 の場合、

[code]

    (b ^ (b >> 31)) = 0x00000001
    
[/code]

ですね。

* * *

以下、`myabs()` の説明です。

絶対値を求めるなら、

  * 元の数値が 0以上ならそのまま
  * 元の数値が負数なら符号を反転

とすれば良いわけです。ここに、2の補数の

  * 全てのビットを反転して +1 すると値の符号が反転する。
  * 最上位ビットは符号である。

という特徴を活かします。

`b >> 31` は、最上位ビットで他の31ビットを塗りつぶします。  
つまり、

  * `b` が 0 以上なら 0
  * `b` が負数なら -1 (全てのビットが 1)

となります。

従って `(b ^ (b >> 31))` は

  * `b` が 0 以上なら何も起きない (`b >> 31` が 0 だから)
  * `b` が負数なら `b` のビットが全て反転する (`b >> 31` は全てのビットが 1 だから)

ということになります。  
また `- (b >> 31)` の部分ですが、これは

  * `b` が 0 以上なら 0 (`b >> 31` が 0 だから)
  * `b` が負数なら +1 (`b >> 31` が -1 だから)

となります。

以上の処理により、

  * `b` が 0 以上なら何もせず `b` のまま
  * `b` が負数ならビットを反転して +1 する (つまり符号を反転する)

という処理が実現できていることになり、絶対値が求まります。

