ページ 11

ビット演算子について

Posted: 2009年2月10日(火) 20:30
by たか
ビット演算はどういう時に使えばいいのでしょうか?
演算の意味は理解しましたが、使いどころが分かりませんでした。
抽象的な質問ですが、よろしくお願いします。


http://dixq.net/sm/w2.html
質問とは関係ありませんがこのページが文字化けして正常に表示されません。
エンコードを変更してみましたが、文字化けは直りませんでした。
新しいトピックを立てるわけににもいかなかったので、ここで報告しました。

Re:ビット演算子について

Posted: 2009年2月10日(火) 21:21
by 御津凪
2の乗数の乗除を、シフト演算で代替することで高速化を図ることができたり、
DirectX 等のカラー情報から特定の色情報だけを取り出しや置き換えなどが出来たり、
簡易的な暗号化を施したり…などが上げられます。

こうして挙げると、主にビットを扱う程度の処理で使用するのが多いですね。
なので、普段はあまり全ての演算子を扱うことが少ないです。

ゲームなどの実用的な方法として、たとえば、
#define FLAG_COUNT 1024 // フラグ数

static unsigned long sFlagData[FLAG_COUNT >> 5]; // フラグデータ

// 指定した位置のビットフラグを取得
// id は取得するビット番号、戻り値はそのフラグ値。
int get_flag( int id ){
    return (sFlagData[id >> 5] >> (id & 31)) & 1;
}
// 指定した位置のビットフラグを立てる
// id は立てるビット番号
void set_flag_on( int id ){
    sFlagData[id >> 5] |= (1 << (id & 31));
}
// 指定した位置のビットフラグを降ろす
// id は降ろすビット番号
void set_flag_off( int id ){
    sFlagData[id >> 5] &= ~(1 << (id & 31));
}
このようにフラグを省スペースで管理することが出来ます。

Re:ビット演算子について

Posted: 2009年2月10日(火) 21:59
by たか
なるほど、構造体を用意してフラグを管理しなくてもすみますね。
ビット演算は処理が高速と聞いていたので、何らかの計算に使用するイメージがありました。
サンプルコード参考にします。

>2の乗数の乗除を、シフト演算で代替することで高速化を図ることができたり
num = 5 * 5;
num = 5 << 1;
こういうことですよね。

暗号化は興味があるので調べてみます。
回答有難うございました。

Re:ビット演算子について

Posted: 2009年2月10日(火) 22:12
by 御津凪
5 * 5 と 5 << 1 では計算結果が違いますよ。
5 << 1 は 5 * 2 と等価です。

X << N と変数で考えた場合、
X を 2 の N 乗で掛ける、と覚えておくと分かりやすいかと思います。

あと、他にビット演算でよく使われるアルゴリズムとして、
圧縮や解凍、画像処理、ハッシュ、ランダム値生成などがあります。

Re:ビット演算子について

Posted: 2009年2月10日(火) 22:33
by たか
お恥ずかしい、勘違いしてました。

>X << N と変数で考えた場合、
>X を 2 の N 乗で掛ける、と覚えておくと分かりやすいかと思います。

よく覚えておきます。
勘違いしたままプログラムを組むところでした。

Re:ビット演算子について

Posted: 2009年2月10日(火) 22:48
by non
マイコンではよく使います。マイコンにはポートと呼ばれる入出力するためのアドレスが
あります。この各ビットにスイッチやLEDやモータをつなぎます。
例えば、スイッチ4個をポートの下位4ビットに接続した場合、B0のスイッチが押されて
いるか調べるときに0x01と&します。これをマスクといいます。

8個LEDをつないで、ナイトライダーの車のようにLEDを順番に転倒させたりしたものです。
(ナイトライダーって知ってる人?いる?)
こんなとき、シフトを使います。

Re:ビット演算子について

Posted: 2009年2月10日(火) 23:29
by たか
ナイトライダーは分かりませんが、マスクとシフトのプログラムを書いてみました。
また勘違いしているかもしれません。合っているでしょうか?
if(PORT_ADRESS & 0x01)
    //B0のスイッチが押されている
for(int i=0; i < 8; i++)
    PORT_ADRESS = 0x01 << i;

Re:ビット演算子について

Posted: 2009年2月11日(水) 00:45
by たかぎ
> ナイトライダーは分かりませんが、

↓です。
http://www.youtube.com/watch?v=LbJDP0kzhtg

Re:ビット演算子について

Posted: 2009年2月11日(水) 05:08
by Mikan
>8個LEDをつないで、ナイトライダーの車のようにLEDを順番に転倒させたりしたものです。
ナイトライダー・・・ なつかしいw 
車が喋ったりジャンプしたり、久しぶりに見たくなりましたw

Re:ビット演算子について

Posted: 2009年2月11日(水) 05:18
by Dixq (管理人)
0と1の信号がいくつかセットになってるような場合によくビット単位で使いますよね。
例えば「ゲームのコントローラーのキー入力状態」

0なら押していない
1なら押している

こうしてキー入力をチェックしたりよくします。
1バイトは8ビットなので、1バイト用意するだけで、8個も0と1を入れる入れ物が用意出来るわけです。
今コントローラーの各キーが以下のように各ビットに対応しているとします。

 下  上  左  右  A  B  L  R
[ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] 

このように対応しているとして、今Lキーが入力されているとすると

 下  上  左  右  A  B  L  R
[ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 0 ] [ 1 ] [ 0 ] 

こんな感じになるわけですね。
2進数で00000010は10進数で言う2ですが、そういう考えはせず、
「右から2番目のビットがたっているか?」という感じで判定していきます。
こうすることで、いちいち変数を用意するより少ないスペースで効率よく判定出来るわけです。
 

Re:ビット演算子について

Posted: 2009年2月11日(水) 08:33
by non
>また勘違いしているかもしれません。合っているでしょうか?

あってますよ。
スイッチはマイコンの場合、回路を簡単にするため、ONのとき0になる
回路を作ることが多いです。ですから、
if(~PORT_ADRESS & 0x01)
のように反転させることがよくあります。

Re:ビット演算子について

Posted: 2009年2月11日(水) 13:00
by たかぎ
> 0なら押していない
> 1なら押している

ハードウェアを直接制御する場合は、押しているときに0になる(負論理)のケースの方が多いですね。