ビット演算に関する補足
coskx
1.ビット演算子
ビット演算は整数型変数(char型,int型など)に対して行なわれる演算である。変数のビットパターンに対する演算である。
(1)シフト演算
演算子
意味
<<
左シフト
>>
右シフト
この演算は,整数におけるコンピュータの内部表現において,右や左にずらす演算である。(もともとコンピュータ内部で数値は,2進数で扱われているビットパターンである)
例えば
「12<<3」は12を左に3つずらす意味であり,12はビットパターンで表すと「1100」なので左に3つずらすと「1100000」となりこれは96である。
「12>>2」は12を右に2つずらす意味であり,12はビットパターンで表すと「1100」なので右に2つずらすと「11」となりこれは3である。
一般に整数を左に1つずらすと2倍になり,2つずらすと4倍になり,3つずらすと8倍になり4つずらすと16倍になる。逆に右に1つずらすと1/2倍になり,2つずらすと1/4倍になり,3つずらすと1/8倍になり,4つずらすと1/16倍になる。
例
int x,y;
の時
y=x/1024;
と
y=x>>10;
は同じ意味になる。
右ずらしのとき,unsignedで修飾された変数とsignedで修飾された変数で振る舞いが異なる.
unsignedで修飾された変数 通常の右ずらし
signedで修飾された変数 最上位ビットの値が保たれる.
例
unsigned char myvalue=0xf0; のとき
myvalueは11110000で,myvalue>>3 は00011110になり0x1eになる.
0xf0は符号なし1バイト整数では240 1/8倍すると30(0x1e)である
signed char myvalue=0xf0; のとき
myvalueは11110000で,myvalue>>3 は11111110になり0xfeになる.
0xf0は符号有1バイト整数では-16 1/8倍すると-2(0xfe)であり,つじつまが合っている.
(2)論理演算
演算子
意味
&
ビットごとのand演算
|
ビットごとのor演算
^
ビットごとのxor演算(排他的OR)
~
全ビット反転
例 「157&241」はビットパターンでは「10011101&11110001」となり,以下のように結果は10010001すなわち145となる1001 1101
& 1111 0001 ビットごとに縦にアンド演算を行う。繰り上がり繰り下がりはない。
-------------
1001 0001
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
第2変数
1111 0001
F1
241
結果
1001 0001
91
145
例 「157|241」はビットパターンでは「10011101|11110001」となり,以下のように結果は11111101すなわち253となる
1001 1101
| 1111 0001 ビットごとに縦にオア演算を行う。繰り上がり繰り下がりはない。
-------------
1111 1101
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
第2変数
1111 0001
F1
241
結果
1111 1101
FD
253
例 「157^241」はビットパターンでは「10011101^11110001」となり,以下のように結果は01101100すなわち108となる
1001 1101
^ 1111 0001 ビットごとに縦に排他オア演算を行う。繰り上がり繰り下がりはない。
-------------
0110 1100
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
第2変数
1111 0001
F1
241
結果
0110 1100
6C
108
例 「~157」はビットパターンでは「~10011101」となり,以下のように結果は01100010すなわち98となる
~ 1001 1101 ビットごとに反転演算を行う。繰り上がり繰り下がりはない。
-------------
0110 0010
2進法表現
16進法表現
10進法表現
第1変数
1001 1101
9D
157
0110 0010
0
62
98
使用例
int k;
のもとで
if (k%256==0) {
は
if ((k&0xff)==0) {
と同じ意味になる。2のべき乗の時のみ使える
int k,k1,k2,k3;
のもとでk1=k2=k3=0;
for (k=0; k<10000; k++) {
k1++;
k1&=3;
k2++;
k2&=7;
k3++;
k3&=0xf;
:
:
}
では
k1の値は0,1,2,0,1,2,0,1,2,・・・
のように0,1,2を繰り返し,
k2の値は0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,・・・
のように0,1,2,・・,7を繰り返し,
k3の値は0,1,2,3,・・,13,14,15,0,1,2,3,・・,13,14,15,0,1,2,3,・・,13,14,15,0,1,2,3,・・
のように0,1,2,・・,13,14,15を繰り返す。
unsigned int x:
のもとで,if (x&1==1) はxの第0ビット(右端)が1だったらと意味になる.
if (x&2==2) はxの第1ビット(右から2番目)が1だったらと意味になる.
if (x&4==4) はxの第2ビット(右から3番目)が1だったらと意味になる.
if (x&8==8) はxの第3ビット(右から4番目)が1だったらと意味になる.
if (x&0x10==0x10) はxの第4ビット(右から5番目)が1だったらと意味になる.
(3)ビット演算子利用上の注意
ビット演算子の優先順位は低いので「()かっこ」を利用しておくとよい。
例 int k1,k2 のもとで
k2=k1<<4+1;
はそのままでは
k2=k1<<(4+1);
のように解釈される。もし
k2=(k1<<4)+1;
の記述をしたければ,そのように書く必要がある。同様に
if (k2==k1&0xff) {
はそのままでは
if ((k2==k1)&0xff) {
のように解釈される。もし
if (k2==(k1&0xff)) {
の記述をしたければ,そのように書く必要がある。
(4)「ビット演算子」+「=」
ビット演算子においても「&=」などの表現ができる。
文
意味
x <<= 3;
x = x<<3;
x >>= 4;
x = x>>4;
x &= 0xf;
x = x & 0xf;
x |= 0x55;
x = x | 0x55;
x ^= 0xffff;
x = x ^ 0xffff;
2.例1
次の例はunsigned short
int型引数の指定したビットが0か1かを返す関数である.
例えば0x5fの第4ビットは(0x5fは101
1111なので)1である.
同様に0x500の第8ビットは(0x500は101
0000 0000なので)1である.
(ビット番号は右から0,1,2,3...と数える)
#include <stdio.h>
int checkBit(unsigned short int value, int bitnumber)
{
int ret=0;
int i=0;
unsigned short int mask=1;
for (i=0; i<bitnumber; i++) mask<<=1;
if (value & mask) ret=1;
return ret;
}int main()
{
unsigned short int x;
int bitnumber;
int ret;
x=1;
bitnumber=0;
ret=checkBit(x,bitnumber);
printf("x=%d x=%x bitnumber=%d ret=%d\n",x,x,bitnumber,ret);
x=0x5f;
bitnumber=4;
ret=checkBit(x,bitnumber);
printf("x=%d x=%x bitnumber=%d ret=%d\n",x,x,bitnumber,ret);
x=0x500;
bitnumber=8;
ret=checkBit(x,bitnumber);
printf("x=%d x=%x bitnumber=%d ret=%d\n",x,x,bitnumber,ret);
x=0x500;
bitnumber=7;
ret=checkBit(x,bitnumber);
printf("x=%d x=%x bitnumber=%d ret=%d\n",x,x,bitnumber,ret);
}/***************************
x=1 x=1 bitnumber=0 ret=1
x=95 x=5f bitnumber=4 ret=1
x=1280 x=500 bitnumber=8 ret=1
x=1280 x=500 bitnumber=7 ret=0
***************************/
3.例2
次の例はunsigned short
int型引数の0でない最上位のビット番号を返す関数の例である.
例えば0x5fは1011111なので0でない最上位のビット番号は6である.同様に0x7ffは10である.
#include <stdio.h>
int geNumberBits(unsigned short int value)
{
int cnt=0;
int i=0;
unsigned short int mask=1;
while (mask) {
if (value&mask) cnt=i;
mask<<=1;
i++;
}
return cnt;
}int main()
{
unsigned short int x;
int n;
x=1;
n=geNumberBits(x);
printf("x=%d x=%x n=%d\n",x,x,n);
x=0x5f;
n=geNumberBits(x);
printf("x=%d x=%x n=%d\n",x,x,n);
x=0x7ff;
n=geNumberBits(x);
printf("x=%d x=%x n=%d\n",x,x,n);
}/***************************
x=1 x=1 n=0
x=95 x=5f n=6
x=2047 x=7ff n=10
***************************/
課題1.与えたunsigned char型変数の下位2ビットを1にした値を返す関数unsigned char set11(unsigned char
value)
を作りなさい.ただし,上位6bitを変更してはならない.
次のmain関数でチェックし,正しい結果になることを確かめなさい.(part0ex1.c)
#include <stdio.h>
unsigned char set11(unsigned char value)
{
ここを作る
}int main()
{
unsigned char x,y;
for (x=0; x<10; x++) {
y=set11(x);
printf("x=%x y=%x\n",x,y);
}
}/********実行結果***********
x=0 y=3
x=1 y=3
x=2 y=3
x=3 y=3
x=4 y=7
x=5 y=7
x=6 y=7
x=7 y=7
x=8 y=b
x=9 y=b
***************************/
課題2.与えたunsigned char型変数に1であるビットが何個あるかを返す関数int countOnes(unsigned char
value)
を作りなさい.
次のmain関数でチェックし,正しい結果になることを確かめなさい.(part0ex2.c)
#include <stdio.h>
int countOnes(unsigned char value)
{
ここをつくる
}int main()
{
unsigned char x;
int y;
for (x=0; x<10; x++) {
y=countOnes(x);
printf("x=%x y=%x\n",x,y);
}
}/********実行結果***********
x=0 y=0
x=1 y=1
x=2 y=1
x=3 y=2
x=4 y=1
x=5 y=2
x=6 y=2
x=7 y=3
x=8 y=1
x=9 y=2
***************************/