2^nの掛け算

2の掛け算をするときに、ビットシフトさせたときに0で埋めるか1で埋めるかという疑問がわいた。

10 * 2 = 20の場合
10(10進数)は、00001010(2進数)である(8+2=10だから)

10 * 2 は、2進数では0埋めの1ビットシフトに相当するので、
00010100(2)である 10進数だと16+4=20(10)であるのでこれは正。

-10 * 2 = -20の場合
10(10)は、00001010(2)である(8+2=10だから)
-10(10)は、00001010(2)+X=100000000(2)で桁上がりをおこす数に相当する。
よって、X=100000000(2)-00001010(2)=11110110(2)

10 * 2 は、2進数では1ビットシフトに相当するので、
11110110(2)の0埋めの1ビットシフトは、
11101100(2)である この補数は00010100(2)だから 16+4=20である。
よって、-10 * 2 = -20 が成り立つ。

11110110(2)の1埋めの1ビットシフトは、
11101101である この補数は00010011(2)だから 16+2+1=19である。
よって、-10 * 2 = -19になってしまうので、これは成り立たない。

よって常に、ビットシフトさせて0で埋める。



次に、桁あふれの場合を考えてみる。
10 * 16 = 160の場合
10(10)は、00001010(2)である(8+2=10だから)
10 * 16 は、10 * 2^4 なので、2進数では4ビットシフトに相当する。
00001010(2)の単純な4ビットシフトは、10100000(2)である。
これは、符号反転を起こしていて、-01100000(2)=-96である。
符号付き8ビットという制限がある場合、表現できる数は、
-128〜0〜127(10) 80〜00〜7F(16) 10000000〜00000000〜01111111(2) である。
よって、オーバーフローをおこしている。これを抑制して。
 a=10;
 b=16;
 cal=a * b;
 if    ( cal > 127  ) then ans= 127;
 elsif ( cal < -128 ) then ans=-128;
 else  ans=cal;でなにもしない
といったような処理が"今回は"必要になる。

ここからは、VHDL風に記述してみる。

a(7 downto 0) <= "00001010"; の正の数の場合、つまりa(7)='0'の場合。
4ビットシフトさせる場合には、桁上がりして残らない4ビット
つまり、a(6 downto 3) のうちどれか1である時、に 
ans<=127 つまり ans<="01111111";で最大値を返す。
 if ( a(7)='0' ) and
    ( ( a(6) or a(5) or a(4) or a(3) ) = '1' ) 
  then
    ans<="01111111";
 end if; 

a=-10
a(7 downto 0) <= "11110110"; の負の数の場合、つまりa(7)='1'の場合。
4ビットシフトさせる場合には、桁上がりして残らない4ビット
つまり、a(6 downto 3) がいずれか0である時、
各ビットをnotしてどれかが1であるときに 
ans<=-128 つまり ans<="10000000";で最大値を返す。
 if ( a(7)='1' ) and
    ( ( not a(6) or not a(5) or not a(4) or not a(3) ) = '1' ) 
  then
    ans<="10000000";
 end if; 

次回に続く。

ここから嘘!

<del>ここで、排他的論理和 xor を使うと、
  x y (x xor y)
  0 0     0
  0 1     1
  1 0     1
  1 1     0
となる。

よって、目的は、どれかのビット全て一緒か否かを判定すればよいので、
 ( a(6) xor a(5) xor a(4) xor a(3) ) ='1'
と統合することができる。

 統合すると、
  if ( a(6) xor a(5) xor a(4) xor a(3) ) ='1' ) then
    if a(7)='0' then ans<="01111111";
    else             ans<="10000000";
    end if;
 end if; 

で書き表せる。</del>

ここまで嘘


( よく、00001010(2)の補数は、11110110(2) という )
( ※ 68(10)の補数は32(10) そろばんを昔"習わされた"人ならよくわかると思う、わからない人はそろばんで視覚的に理解できるとおもう。というか、引き算で皆無意識にやっているはず )


※(人間が計算できるレベルでやるので、8ビット固定の符号付き(C言語っぽい表現だと)signed int8)とした。