多倍長整数演算

レポートの2つ目の課題。
多倍長演算は結局ただの筆算なので実装は楽だろう。
でも、それじゃ自分の勉強にならないのでネタを探していた。*1
多倍長演算の実装には

  1. ビット列を符号なし整数として保持。符号情報を別に扱う。
  2. ビット列に符号情報まで埋め込む。

の2通りがある。RubyのBignumとかは前者。
後者の方法はつまりビット列を2の補数表現の整数などと解釈するということ。

ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか

ハッカーのたのしみ―本物のプログラマはいかにして問題を解くか

  • 作者: ジュニア,ヘンリー・S.ウォーレン,Jr.,Henry S. Warren,滝沢徹,玉井浩,鈴木貢,赤池英夫,葛毅,藤波順久
  • 出版社/メーカー: エスアイビーアクセス
  • 発売日: 2004/09
  • メディア: 単行本
  • 購入: 35人 クリック: 732回
  • この商品を含むブログ (129件) を見る

には後者の方法で乗算を行う実装が紹介してあった。
この方法では

1.まず符号なし乗算。

ビット列全体を一つの整数としてみて、負数は2の補数が使われているとすると
(Xがmビット整数xを符号なしとして解釈した値だとすると)
X=\left\{ \begin{array}{cc} x & (x\geq 0) \\ x + 2^m & (x < 0) \\ \end{array}\right.
になる。
なので、xの符号ビットをs_x(xが0以上なら0、それ以外なら1)と表すことにすると
mビット整数xとnビット整数yを符号なし乗算した値は
XY = (x + s_x2^m)(y+s_y2^n) = xy + xs_y2^n+ys_x2^m+s_xs_y2^{m+n}
となる。

2.実際に求めたい値はxyなので邪魔なものを引く。

xyの結果は必ずm+nビット以下の整数になるのでs_xs_y2^{m+n}の項はオーバーフローするか0なので無視できる。
よって
xy = XY - xs_y2^n-ys_x2^m

という感じ。要するに

  1. XYを普通に筆算で求める
  2. x, yの正負にしたがって邪魔なものを消す。(2のべき乗がかかるので結局多倍長シフトをすることになる)

うーん...この方法は生のバイト列を乗算できるという利点があるけど、それだけな気もするな。
符号は別に管理した方が速度的には効率良いよな〜。この方法はパス。

他に、奇抜さを狙うなら-2進数とかで実装してみると面白いかも。符号情報を扱う必要なし!これで行ってみようかな。
どうでもいいけど、やっぱ数学って強力な道具だと実感。

*1:自分は基本的に面白いことがしたい人間なので。レポートの評価と面白さは多分関係ないだろうけど^^;