概ね方位不定だが多分割と偏っている
スポンサーサイト
--年--月--日 (--) | 編集 |
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。


C ビット演算子補足
2006年09月07日 (木) | 編集 |
前回訳分からんわー、と投げ出したビットパターン表示関数の補足。
同僚に聞いてみたところ、それなりの頻度で扱う可能性があるらしい。

避けて通れないようだ。

仕方ない。それなら真っ向から受けて立つまでだ。
俺が折れるか、疑問が消えるか…2つに1つ! たまらねえ!

このスリルが俺の思考を加速するのよ!









そういうわけで手っ取り早く分かっている人に聞いてみた。

ビット演算子、ということでバッファとやらでイメージする必要があるのだそうだ。
バッファとか言われてもイマイチよく分からないが、要するに2進数らしい。
2進数なので、例えば実際には1という数字が入力されていても、

0000 0000 0000 0001

コンピュータの中ではこのように扱われているわけだ。
これが分かれば後は簡単で、

0000 0000 0000 0001 を右に15個シフト
    ↓
0000 0000 0000 0000 になる(右から2桁目の1はシフトして消える)

0000 0000 0000 0000 と0x0001の論理積を求める
    ↓
0000 0000 0000 0000 になる

0000 0000 0000 0000 %d(整数値)として出力する
 ↓
当然0に。

なので、整数値xを右に15ビットシフトさせた値は0として出力される。
同様のことをループ文でiが右に0個シフトするまで繰り返す。

14個右にシフト→同様に0を出力
13個右にシフト→同様に0を出力
以下略
1個右にシフト→同様に0を出力


これで0が14個出力される。
そして最後の0個シフト(つまりシフト無し)の時、0000 0000 0000 00001はシフトされないので0000 0000 0000 0001のままであり、これを0x0001でマスクすると0000 0000 0000 0001になり、これを数値として出力すると1になる。
これが一番右端に出力された1ってことだな。

ポイントは、

0か1かの計算(論理積。マスク)をしながら1文字ずつ表示し、
それを15回繰り返している


ことにあったのである。

また、シフトするだけで0x0001でマスクしない場合↓はどうなのかというと、
bitpat_test4.jpgbitpat_test3.jpg
これもよく分からなかった結果だが

例えば8を例にとってみてみると、

0000 0000 0000 1000

内部的にはこう処理されているので、

15個ずらすと
0000 0000 0000 0000 → %dでprintf出力すると0

14個ずらすと
0000 0000 0000 0000 → %dでprintf出力すると0

(中略)

3個ずらすと
0000 0000 0000 0001 → %dでprintf出力すると1

2個ずらすと
0000 0000 0000 0010 → %dでprintf出力すると2

1個ずらすと
0000 0000 0000 0100 → %dでprintf出力すると4

0個ずらすと(シフトしない)
0000 0000 0000 1000 → %dでprintf出力すると当然8

よって、0が12個と1、2、4、8が順番に出力されるので、結果は

0000000000001248

となる。問題なし。
分かってしまえばどうということはない。
やれやれ全くもう。バカバカシー。恐るるに足らねーな。何悩んでたんだか。

よーし俺絶好調

調子に乗って左にローテイトする関数も作ってみる。
ローテイトってのはシフトして消えたはずのものが右側から出てくるってことだ。

xを1ビット左にローテイトするには、
x>>15とx>>1の論理和を求めればよいらしい(理屈は不明だが)。
なので、xをnビット左にローテイトしたいなら、
1ビット左にローテイトする処理をn回繰り返せばいいことになる。
なので、

unsigned rotl(unsigned x, int n)
{
 int i;
 for(i=n;i>0;i--)
  x=(x>>15) | (x<<1);
 return(x);
}


こうなる。
後はこれをメイン関数で呼び出せばよし。

void main(void)
{
 unsigned x;
 int n;
  while("scanf("%d %d",&x,&n)!=EOF)
 printf("%x\n",rotl(x,n);
}


こんな風に。unsignedというのは符号無し(つまり正の数)を意味するそうな。
unsignedなxをrotl関数に渡し、rotl関数からもunsignedな結果を受け取り表示する。

rotate_test.jpgrotate_test2.jpg
こんな感じ

1は0000 0000 0000 0001であり、これを左に3つローテイトすると
0000 0000 0000 1000になり、これは10進数で言うところの8である。

2は0000 0000 0000 0010であり、これを左に1つローテイトすると
0000 0000 0000 0100になり、これは10進数で言うところの4である。

3は0000 0000 0000 0011であり、これを左に2つローテイトすると
0000 0000 0000 1100であり、これは10進数で言うと12になるはずなんだが…何でcになるんだ? 

はて。


ああ、書式制御文字が16進数だからか。
0000 0000 0000 1100は10進数で言うところの12なので、16進だとcになる。
同様に以下も、

10は0000 0000 0000 1010であり、これを左に2つローテイトすると
0000 0000 0010 1000であり、40になり、16進で表現すると28になる。

2は0000 0000 0000 0010であり、これを左に5つローテイトすると
0000 0000 0100 0000であり、これは10進数で言うところの64であり、16進で表現すると40になる。

OK、問題なし。これにて疑問は解消された。
後顧の憂いなく先に進めるっていいなあ。
スポンサーサイト

コメント
この記事へのコメント
コメントを投稿する
URL:
Comment:
Pass:
秘密: 管理者にだけ表示を許可する
 
トラックバック
この記事のトラックバックURL
この記事へのトラックバック
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。