ビット単位

解決


すかい  2006-03-28 01:07:29  No: 61033

ビット単位で計算をするプログラムがわからないのですが。。。
たとえば、足し算なら
  1010
+ 1111  
------------
 11001 
みたく計算するプログラムを教えてください。


YuO  2006-03-28 01:42:43  No: 61034

ビット単位も何も,普通に計算すればよいだけでは?

int x = 0x0A; // 1010(2)
int y = 0x0F; // 1111(2)

int z = x + y; // 19 : 11001(2)


すかい  2006-03-28 01:52:40  No: 61035

つまり+を使わずに
ビット演算子を使って結果を出したいのですが。


KING・王  2006-03-28 03:24:50  No: 61036

おもしろそうなので作ってみた。

void BitFunc( bool bDataA, bool bDataB, bool bDigitUp, bool* lpbDataC, bool* lpbNextDigitUp )
{
    if( bDataA == bDataB ){ // (1, 1, bDigitUp) or (0, 0, bDigitUp)の場合
        // 桁上がりの値となる
        *lpbDataC = bDigitUp;
        if( bDataA ){  // (1, 1, bDigitUp)の場合
            // 必ず桁上がり発生
            *lpbNextDigitUp = true;
        }else{
            *lpbNextDigitUp = false;
        }
    }else{    // (1, 0, bDigitUp) or (0, 1, bDigitUp)の場合
        // 桁上がりと反対の値となる
        *lpbDataC = !bDigitUp;
        // 桁上がりがある場合、次も桁上がり
        *lpbNextDigitUp = bDigitUp;
    }
}

int main( void )
{
    unsigned short DataA = 0x0A, DataB = 0x0F, DataC = 0x00;
    bool bNextDigit = false, bBitC = false;
    int iBit = 0;
        
    for( iBit = 0; iBit < 16; iBit++ ){
        // iBitの計算
        BitFunc( ((DataA>>iBit) & 0x01), 
                 ((DataB>>iBit) & 0x01), 
                 bNextDigit, 
                 &bBitC, 
                 &bNextDigit );
        // 計算結果の反映
        if( bBitC ){
            DataC |= (0x01<<iBit);
        }
    }//for(iBit)

    printf( "DataC = %X\n", DataC );

    return 0;
}


すかい  2006-03-28 03:28:30  No: 61037

む、むずかしい・・・。
こんなに複雑とは思いませんでした。
フローチャートに直したら多少わかりやすくなるかな。。。


KING・王  2006-03-28 03:35:04  No: 61038

BitFuncの中をもう少し分かりやすく?したものです。
(分かりやすくといっても、下からの桁上がりがある場合とない場合をわけているだけですが。。。)

void BitFunc( bool bDataA, bool bDataB, bool bDigitUp, bool* lpbDataC, bool* lpbNextDigitUp )
{
    if( bDigitUp ){  // 桁上がり有りの場合
        if( bDataA == bDataB ){  // (1,1,1) or (0,0,1)
            *lpbDataC = true;
            if( bDataA ){  // (1,1,1)で桁上がり有り
                *lpbNextDigitUp = true;
            }else{
                *lpbNextDigitUp = false;
            }
        }else{  // (1,0,1) or (0,1,1)
            *lpbDataC = false;
            // 桁上がり発生
            *lpbNextDigitUp = true;
        }
    }else{// 桁上がりなしの場合
        if( bDataA == bDataB ){  // (1,1,0) or (0,0,0)
            *lpbDataC = false;
            if( bDataA ){  // (1,1,0)で桁上がり
                *lpbNextDigitUp = true;
            }else{  // (0,0,0)で桁上がりなし
                *lpbNextDigitUp = false;
            }
        }else{  // (1,0,0) or (0,1,0)
            *lpbDataC = true;
            // 桁上がりなし
            *lpbNextDigitUp = false;
        }
    }
}


すかい  2006-03-28 03:43:59  No: 61039

わざわざありがとうございます。
これって、やっぱりフローチャートに直すとすごい複雑になるものでしょうか?
今、自分で直してるのですが、いまいちわからないもので。


KING・王  2006-03-28 04:11:54  No: 61040

このBitFunc()は筆算の考え方を応用して、特定のnビットの値に関して計算しています。
(1)加算される2つの値のそれぞれのnビットの値がbDataAとbDataBで表されています。
(2)下位の桁からの繰り上がりをbDigitUpで表しています。
(3)このbDataAとbDataBとbDigitUpの足し算を行い、この桁の値を*lpbDataCと、
繰り上がりの値*lpbNextDigitUpを求めています。

ここで、もっとも単純にすると、bDataA、bDataB、bDigitUpはそれぞれ、0か1しのいずれかなので、
組み合わせとしては2×2×2の8通りあります。
それぞのれの場合の、*lpbDataCと*lpbNextDigitUpを用意しておき、
BitFunc()の中で、その値を返すのでもOKです。

後は、main()側で一番下位のビットから順番に
(1)n番目の桁の値をBitFunc()で計算
(2)その結果をDataCに反映
(3)BitFunc()で求まった繰り上がりを次の桁の計算に利用
を桁数分(ビット数分)繰り返しています。

※一番下位の計算においては、下位桁からの繰り上がりはないので、初期値として*lpbNextDigitUpをfalse(0)にしておく。
※結果は最初に0で初期化しておくと、各桁の計算結果を“|=”で反映させることができる。


すかい  2006-03-28 04:17:04  No: 61041

なるほど!!
完璧に理解できました!
ありがとうございました。


fuku  2006-03-28 04:32:11  No: 61042

もう解決されたようですが、作ってみたので別解として載せてみます。

bool BitAdd(bool val1,bool val2,bool &digup){
   //戻り値:計算結果
   //val1,val2:左、右オペランド
   //digup:[入出力]桁上がりの有無
   bool val3=digup;
   digup=((val1&&val2)||(val1&&val3)||(val2&&val3));
   return val1^val2^val3;
}
bool Add(const void *src1,const void *src2,void *dst,unsigned int size){
   //戻り値:オーバーフローの有無
   //src1,src2:左、右オペランド
   //dst:結果格納先
   //size:src1,src2,dstの有効バイト数
   unsigned char *b_src1=(unsigned char*)src1;
   unsigned char *b_src2=(unsigned char*)src2;
   unsigned char *b_dst=(unsigned char*)dst;
   unsigned int i,j;
   bool digup=false;
   memset(dst,0,size);
   for(i=0;i<size;i++){
      for(j=0;j<8;j++){//注:1byte=8bit前提。
         if(BitAdd((b_src1[i])&(0x01<<j),(b_src2[i])&(0x01<<j),digup)){
            b_dst[i]|=(0x01<<j);
         }
      }
   }
   return digup;
}

int main(){
   unsigned long val1=0xba987654,val2=0xfedcba98,ans;
   if(Add(&val1,&val2,&ans,sizeof(unsigned long)))puts("オーバーフロー発生");
   printf("ans=%x",ans);
   getchar();
   return 0;
}


yoh2  2006-03-28 06:28:33  No: 61043

別の視点からの方法をふと思いついたので書いてみます。
固定ビット数のみ対応、オーバーフロー検知なし、と手抜きしてますがご容赦のほどを。
考え方は後の方に書いています。

/* a+bの計算結果を返す。 */
unsigned Add(unsigned a, unsigned b)
{
    while(b != 0){
        unsigned next_b = (a & b) << 1;
            a ^= b;
            b = next_b;
    }

    return a;
}

/* 上関数の再帰版。効率はともかく、考え方はこちらの方がわかりやすいと思う */
unsigned RecursiveAdd(unsigned a, unsigned b)
{
    if(b == 0){
        return a;
    }
    else{
        return RecursiveAdd(a ^ b, (a & b) << 1);
    }
}

/* 利用サンプル */
int main()
{
    unsigned val1 = 0xba987654, val2 = 0xfedcba98;

    printf("%x + %x = &#92;n", val1, val2);
    printf("    %x (by Add())&#92;n", Add(val1, val2));
    printf("    %x (by RecursiveAdd())&#92;n", RecursiveAdd(val1, val2));
    printf("    %x (by '+' operator)&#92;n", val1 + val2);

    return 0;
}

考え方:

a + b == (繰り上がりを無視した足し算の結果) + (繰り上がり)
      == (a ^ b) + ((a & b) << 1)                    (*)
なので、
a_1 = a ^ b
b_1 = (a & b) << 1
とすれば、a + b = a_1 + b_1。
ここから、a_1とb_1にさらに式(*)を適用してa_2、b_2をつくって、さらに…… とすることができます。
このようにすると、実はb_iの下位iビットは必ず0になります(証明は省略)。
nビット数の下位nビットが0とは、単なる0ですので、最大でもn回変形を繰り返せば、0との足し算になります。
なので、b_iが0になるまで変形を繰り返し、0になったときのa_iを返せば、それがa + bの結果になります。


fuku  2006-03-29 03:43:21  No: 61044

>(fuku 2006/03/27(月) 19:32:11)
>bool Add(const void *src1,const void *src2,void *dst,unsigned int size){
>unsigned char *b_src1=(unsigned char*)src1;
>unsigned char *b_src2=(unsigned char*)src2;
ああ・・・const消しちゃってる(汗)
以下のように訂正します・・・
const unsigned char *b_src1=(const unsigned char*)src1;
const unsigned char *b_src2=(const unsigned char*)src2;


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加