配列から任意のビット数のデータを取り出す方法

[戻る]
773 2005/06/24(金) 22:41:45
初めて質問をさせてもらいます。

VC++6.0 MFC Windows2000で作業をしています。

任意のビットデータが BYTEの配列に並んでいるデータから
それぞれのビットデータを取り出したいと考えています。

ビット演算子を調べて下記のプログラムを作ってみたのですが
何か良い方法はないでしょうか?

 BYTE Bit;
 BYTE Buf[4]; 
 DWORD DataNumber;
 DWORD i,Temp,Temp2,Temp_s,Temp_a;

 BYTE Data[500];  //データが詰まっているとして
 DWORD Data2[500]; //この配列に取り出したい

 Bit=17;          //データのビット数(任意)
 DataNumber=100;  //データの個数(任意)

 for(i=0;i<DataNumber;i++){
  
  Temp=i*Bit;
  Temp_s=Temp/8;
  Temp_a=Temp%8;

  Buf[0]=Data[Temp_s+0];
  Buf[1]=Data[Temp_s+1];
  Buf[2]=Data[Temp_s+2];
  Buf[3]=Data[Temp_s+3];

  Temp2=(Buf[0]<<24)+(Buf[1]<<16)+(Buf[2]<<8)+Buf[3];

  Temp2=Temp2<<Temp_a;
  Temp2=Temp2>>(32-Bit);

  Data2[i]=Temp2;

 }

ちなみに
ポインタをビット単位で移動して、任意のビット数を
読み込む事は可能でしょうか?

reshia 2005/06/24(金) 23:23:30
よくわからないのですが、
>ビット演算子を調べて下記のプログラムを作ってみたのですが
このプログラムではダメだったということでしょうか?

>任意のビットデータが BYTEの配列に並んでいるデータから
>それぞれのビットデータを取り出したいと考えています。
たとえば、
 10101010111010101101000110101011
というビットの並びが、配列Dataの中に8ビットずつ入っていて、つまり
[0] = 10101010
[1] = 11101010
[2] = 11010001
[3] = 10101011
となっていて、ここから、任意のビット数(Bit)分だけのデータを取り出したい
そういうことでしょうか?

reshia 2005/06/24(金) 23:26:14
あ、だから、
たとえば3ビットずつ取り出したいなら、
Data2[0]=101
Data2[1]=010
Data2[2]=101
Data2[3]=110
Data2[4]=101
Data2[5]=011
Data2[6]=010
Data2[7]=001
Data2[8]=101
Data2[9]=010
Data2[10]=11
となるということでしょうか?

まきじ [E-Mail] 2005/06/24(金) 23:46:39
共用体とかどうでしょうか?

union {
   BYTE Buf[4];
   struct {
      unsigned int bit0:1;
                :
                :
      unsigned int bit31:1;
   };
};

773 2005/06/24(金) 23:53:39
reshiaさん
ご返答ありがとうございます。
考え方は、そのとうりです。

説明不足で申し訳ありません。

目的の結果を得るために、試行錯誤し
今回初めて、ビット演算子を利用しました。

もっと一般的な方法などが在るのではないかと
思い、質問させていただきました。

膨大な量のデータを処理したいので、少しでも
動作を速くしたいと考えております。

何か、助言等ありましたら よろしくお願いします。

reshia 2005/06/25(土) 01:04:02
# 私が考えたのは・・
# 間違っているかもしれないので突っ込みよろしくおねがいします
オリジナル(?)のビット列の下位ビットがData[]配列の若い要素に入っている
つまり
... Data[3] Data[2] Data[1] Data[0]
という感じにビットが格納されているものとして・・。

SS0)
普通にint型の3-7ビット(計5ビット)を取り出したいときは、
「(i>>3)&0x1F」で取り出せます。
これと同じような処理を行います。

SS1)
Bit=17-bitずつ取り出すとき、
まず最初は(つまりforループのi=0のとき)、
0ビット目から16ビット目までを取り出してData2[0]に格納するわけです。
(i番目ならiビット目から(i+Bit-1)ビット目まで)
> h = i;
> t = i+Bit-1;
# h:head, t:tail
とすると、hビット目がData[]配列のどの要素に入っているかをまず調べます。
少し考えればわかると思うので、割愛します。

SS2)
hビット目がData[index_h]に入っていたとします。
そこからBitビット分のデータを取り出すのですが、単純にはできません。
tビット目がData[index_h]にあれば単純なのですが・・(SS0と同様の操作で良い)
とりあえず、Data[index_h]で必要なデータだけ取り出します。
必要なデータというのは、Data[index_h]は8-bitの情報を持っていますが
実際のところ、Data[index_h]の (h%8) 〜 (h%8+Bit-1)のデータを取り出します。

たとえば、Bit=5, i=1のときは、h=5, t=9 で、index_h=0になりますが
実際には、Data[0]の5-7ビット目とData[1]の0-1ビット目が目的のビットに当たります。

とまぁ、こんな感じで書きすぎるのもよくないと思いますので、
後は・・、わかりますよね?
気をつけるのは、index_h番目からデータを取り出すときと、
Data[]配列の最後の方からデータを取り出すときに、配列オーバーしないことです。

取り出せたら、Data2[i]に入れるだけです。

がんばってください。

tib 2005/06/25(土) 01:36:34
> 膨大な量のデータを処理したいので、
> 少しでも動作を速くしたいと考えております。
> 何か、助言等ありましたら よろしくお願いします。
膨大、というのが実際どの程度のレベルなのか解りませんが、速さよりもまずは動くもの
を作った方がいいのではないでしょうか。より速いものを...とあれこれ悩んでいる時間
と、とりあえず動くものを動かしたまま放っておく時間とを比べたら、どちらが多くなる
でしょうね?

ちょっとおもしろそうだったので、こんなのを作ってみました。参考になりますか?

DWORD Cxxxxx::extractBits(BYTE *pByte, int nFrom, int nLength)
{
    DWORD    dwRet    =    0;
    DWORD    dwMask    =    0xffffffff;
    DWORD    *pDW;

    dwMask    <<=    (32 - nLength);
    dwMask    >>=    nFrom;

    pDW        =    (DWORD*)(pByte + (nFrom/8));
    dwRet    =    *pDW & dwMask;
    dwRet    >>=    (32 - nFrom - nLength);

    return dwRet;
}

773 2005/06/25(土) 06:40:59
ご返答ありがとうございます。

皆さんのご返答上手く利用できず、苦戦中です。

分かりにくくて申し訳ありませんが..説明を加えて
考えをまとめてみます。

ビットの並びは下記のようになります。

オリジナルのデータが10ビットの場合

ビット並び           000000101000000000100000000100..
↓
8ビット              00000010     10000000     00100000     000100..
↓
正の整数に変換       2            128          32           ..
↓
BYTE配列読に読み込み Data[0]=2    Data[1]=128  Data[2]=32   Data[3]=..
↓
10ビットに分解       0000001010   0000000010   0000000100   ..
↓
正の整数に変換       10           2            4            ..
↓
DWORD配列に代入      Data2[0]=10  Data2[1]=2   Data2[2]=4

最終的に 配列Data2に正の整数値として代入したいと考えています。

ビットは、右から左に増え、上位ビットがData[]配列の若い方になります


計算過程で
共用体のビットフィールドや、
ポインタで移動して 読み込むとビット並びが
求めたい並びとは、逆になってしまいます。

例えば、

BYTE buf[4];
BYTE *pByte;
DWORD *pDW;

buf[0]=2;      00000010 
buf[1]=128;    10000000
buf[2]=32;     00100000
buf[3]=16;     00010000

pByte=buf;

pDW=(DWORD*)(pByte)

pDWのビットの並びの結果
00010000 00100000 10000000 00000010

出てきてほしい並び
00000010 10000000 00100000 00010000

一個一個並び替えるしかないのでしょうか?
自分は何か考え違いをしているのでしょうか?

まきじ [E-Mail] 2005/06/25(土) 11:12:37
>計算過程で
>共用体のビットフィールドや、
>ポインタで移動して 読み込むとビット並びが
>求めたい並びとは、逆になってしまいます。

共用体で、下位ビットからでも、上位ビットからでも
取り出せると思いますが?

reshia 2005/06/25(土) 16:30:34
# 最終的な目標からはズレてるかも
標準ライブラリにあるものを使えば、
一応、ビット列を表せるので、
もしよければこちらを。

bitset:実行時にサイズを変更できない
vector<bool>:演算ができない(a&bとか)
valarray<bool>:基本的な演算しかない(シフトがなかったり)

あと、BOOSTライブラリを使えば、
dynamic_bitset
というものがあります。
お薦めはこちら。

dairygoods 2005/06/25(土) 20:08:05
> pDW=(DWORD*)(pByte)
> 
> pDWのビットの並びの結果
> 00010000 00100000 10000000 00000010
> 
> 出てきてほしい並び
> 00000010 10000000 00100000 00010000

エンディアン(ビックエンディアン、リトルエンディアン)
について調べてみてください。

古いスレッドには追加発言できません。