#1 変数を覗いてみよう (5)  (98年11月7日 初版)

1.5 左シフト演算子と右シフト演算子  左シフト演算子 (<<) は、指定したビット数だけデータのビットを左にシフト(ず らす)します。左側にはみ出したビットは削除されます。右側の空いたビットには0 が詰められます。  右シフト演算子 (>>) は、右側へ指定ビットだけシフトします。しかし左シフト演 算子とは違って、右シフト演算子は空いた左側のビットに何を詰めるかはマシンによ って違います。  ここで示す例では、符号付きの変数に対しては、符号ビット(正が0、負が1)が 使用されます。符号なしの変数では、0を詰めるようになっています。  演算 c << 3 は、cのビットが左へ3ビットシフトします。同様に演算 c >> 2 は右へ2ビットシフトします。注意すべきことは、変数cの値が変わるのではありま せん。式 (c << 3) が演算結果の値を持つのです。  次のプログラムは、シフト演算子の様子を示すものです。
// list01_07.cpp 
// 左シフト演算子(<<)と右シフト演算子(>>) 
#include <iostream.h> 

//10進数を2進数に変換してプリントする 
void dec2bin(int dec) 
{ 
   // dec2bin.cpp と同じ関数 
} 

int main() 
{ 
    int x, i; 
    cout << "整数を入力してください: x = "; 
    cin >> x; 
    cout  << "     x = "; 
    dec2bin(x); 

    // 左シフト演算 
    cout << "\n左シフトするビット数を入力してください: i = "; 
    cin >> i; 
    cout << "x << i = "; 
    dec2bin( x << i ); 

    // 右シフト演算 
    cout << "\n右シフトするビット数を入力してください: i = "; 
    cin >> i; 
    cout << "x >> i = "; 
    dec2bin( x >> i ); 

    return 0; 
}
 ソースファイル ( list01_07.cpp )

[実行結果]
C:\Source>lst01_07 
整数を入力してください: x = 124 
     x = 00000000 00000000 00000000 01111100    

左シフトするビット数を入力してください: i = 3 
x << i = 00000000 00000000 00000011 11100000    

右シフトするビット数を入力してください: i = 4 
x >> i = 00000000 00000000 00000000 00000111    

C:\Source>lst01_07 
整数を入力してください: x = -124 
     x = 11111111 11111111 11111111 10000100    

左シフトするビット数を入力してください: i = 3 
x << i = 11111111 11111111 11111100 00100000    

右シフトするビット数を入力してください: i = 2 
x >> i = 11111111 11111111 11111111 11100001 
 左シフトとは「2の乗算」と同じことです。nビットの左シフトは、2^nを 掛けることと同じです。コンピュータの計算効率としては、2のべきの乗算を行 うよりシフトする方が実行速度が速くなります。最近のコンパイラでは、プログ ラムの中の「2のべきの乗算」があると「シフト」に変換してコンパイルするも のもあります。 (注意)シフト演算子でシフトするビット数を負の数にすると結果は未定義です。 また、演算子の左側(左オペランド)のビット数よりも大きな数のビットシフト の結果も未定義です。つまり、これらは不正な行為です。 [演習問題1.5]シフト演算の結果の整数値も出力するプログラムを書きなさい。         回答  ここで、これまで使ってきた10進数を2進数に変換する関数 dec2bin()の中 身をみてみましょう。
//10進数を2進数に変換してプリントする 
void dec2bin(int dec) 
{ 
    int size = sizeof(int)*8; 
    for(int i= size -1; i >= 0; i--){ 
        if(  (dec >> i ) & 1 ) 
            cout << '1'; 
        else 
            cout << '0'; 
       if( i % 8 == 0 ) cout << " "; // 1バイトごとに空白で区切る 
    } 
    cout << endl; // 最後に改行 
}
 int型の10進数整数値を仮引数 dec で受け取り、ビットパターンをプリントする 関数です。  まず、int型のビット数 size を計算します。int型は4バイトですから32ビット となります。  各ビットの値は整数値1とのビット&演算で評価します。&演算の規則より右端の ビットの値が0か1かがわかります。  2つの場合があります。右端のビットが0のとき、 dec = ******** ******** ******** *******0 1 = 00000000 00000000 00000000 00000001 より dec & 1 = 00000000 00000000 00000000 00000000 したがって ( dec & 1 ) は整数値0です。  また、右端のビットが1のとき、 dec = ******** ******** ******** *******1 1 = 00000000 00000000 00000000 00000001 より dec & 1 = 00000000 00000000 00000000 00000001 したがって ( dec & 1 ) は1です。  つまり、****で表した右端以外のビットの演算は整数1の側がすべて0なので常に 0となります。  他のビットを調べるには、順次右シフト演算を施して右端へ移して1との&演算を 行えばよいことになります。2行目以降の for文 for(int i= size -1; i >= 0; i--) は32個のビットを、左端のビットから右端のビットへ1つずつ評価して行きます。 左端のビットを評価するには31ビット右シフトします。そして最後の右端はシフト しない、つまり0シフトです。iだけシフトした ( dec >> i ) と1との&をとると、 ビットが1のとき結果は1(つまり真)で、ビットが0のときは0(つまり偽)とな り、これは次の if-else 文で表現できます。 if( (dec >> i ) & 1 ) cout << '1'; // 1をプリント else cout << '0'; // 0をプリント  forループの最後の文 if( i % 8 == 0 ) cout << " "; は、8ビットおきに空白で区切るためのものです。剰余演算子%でiを8で割った余り が0のときに1文字の空白のプリントが実行されます。

| 目次 | 前のページ | 次のページ |

Copyright(c) 1998,1999 Yamada, K