[back]

【雑記】
2010/6/20 多倍長と小数と

先日モンゴメリ乗算(※1)を調べたのでRSAのベースになっている多倍長整数のライブラリの見直しを検討するも、整数のみでは汎用性に欠け面白みが無いとつらつら考えていた所、ふと固定桁10のべき乗による内部表現なら小数のサポートも難しく無いのではと思い立ち試しに作ってみた (ちなみにこの手の実装の難易度の9割は符号化(十進基数では関係無い)と除算になる(笑)

一応ソース内のI_PREC,D_PRECを変更する事で任意の桁精度を得る事ができる;-)
(なおこのページに書いてある内容は内輪向けのネタなので、ソースはよそ行きの整形やコメントの除去等は行っていない、実際眺めるにはそういうソースの方が面白いだろー (自分だけかも) という事で(笑) 動作検証も演算ライブラリとしては不十分なのであくまでサンプル的にという事に留意 ;-)


一応windowsの場合VarDecAdd(oleaut32.dll内)に代表されるAPIで10進小数 (.netのdecimalと同等) がサポートされているが、実際には幾つか難が有り

1. 表現が「浮動」小数である事
decimalの内部表現は28桁の「浮動」小数で表現されている為極端に大きな値と小さな値が計算に混在した場合に桁落ちが発生する,


2. 表現幅が28桁である事
最近では一般的なCobolの内部表現の要件でも最低32桁(確か)であり、DBの表現形式では64桁等も採用されている事を考慮すると一般に10進小数が要求される状況に対応するには少々役不足で相互運用性に難がある.


3. 演算の最下位桁は常に銀行丸めで処理されてしまう.
APIの仕様として演算結果が必ず計算の最下位が銀行丸めによって丸められてしまう為、計算結果は以下のようになってしまう.


decimal a;
a=0.5555555555555555555555555555m;
a/=10;
=> 0.0555555555555555555555555556

a=0.5555555555555555555555555545m;
a/=10;
=> 0.0555555555555555555555555554

結果を格納する際に特定桁以上で自前で丸める事で制御できないかという話もあるが、
例えば演算の中間結果で以下のような値が出てくると

a=0.9999999999999999999999999995m;
a/=10;
=> 0.1

結局上のようになってしまい万全とはいい難く、また銀行丸めは日本ではそれ程一般的では無い事や
計算式をデザインする上で丸め方式を任意又は、非プログラマの直感に即した形で選択できないのは
正直かなり頭が痛い所.

上記は実際には演算の極限付近の状態であるので致命的では無く、せいぜい日常の金銭計算程度なら計算式が固定であれば過程をちゃんと吟味すれば問題無い場合も多いが、計算自体を題材にするには少々頭の痛いのも事実で、また固定式においても安易に式を作るには日常的な (実社会での) 計算には無い概念まで考慮しなければならないのは少々気分が悪い、という事で自前で持っていても悪くも無かろうという所.

信頼性さえ別にすれば(笑) DBや金融計算で扱う程度の精度域ならこれで十分だろう、上記のソースではオーバー/アンダーフローは単にメッセージを出しているだけだが特定用途、例えば金銭計算等では自分で好きなように例外などを組み込めるのも大きいかもしれない.

固定桁でも反復計算でなければ数千桁程度は問題無いので、必要ならdoubleの値域 (およそ±308桁) をカバーするのも悪くない. また10のべき乗を基数にする限り、可変桁への対応もそんなに難しい話では無いと思われるので、気が向いたらこれも作ってみても良いかもしれない.

ただ技術計算には単なる多倍長だけで無く有理数表現も無いと意味が無い、また実質的には多倍長が必要なのは一部の整数論や多項式の反復演算などに限定され、後はアルゴリズムに誤差が混入していないかのチェック用として検算やプロトタイプに使用するのも有用ではあるものの、殆どの(技術計算分野の)実用問題は本当に多倍長が必要なのか考え直すのが妥当な場合が多いのも事実ではある.


まーそんな具合で少々心残りとして頭の中に引っかかっていた、汎用的に使える小数をサポートした任意精度の10進演算ライブラリを書いてみたというトコロ、まだ直接の用途は無いものの将来的な目的の為の最低限の保証と布石(※2)といった具合;-)

---------------

※1) 半分仕事っぽいカンジで扱ったので、概念の模式モデル等はここには提示できないが、内容的は有限体上の乗算 a*b mod N をモンゴメリ領域と呼ばれる空間に変換し 乗算3回+加算1回+シフト+ビットマスク に置き換える演算法、これを用いて最終的には有限体上のべき計算 a^b mod N を高速化するのに使用する、一応RSAの実装に興味がある(?) 人もいるみたいなので手がかり程度というカンジで(笑)

※2) 車輪の再発明と云う無かれ、プログラム作成において万全の保証と100%の設計の柔軟さを得るには極めて重要な話なワケです (抱えてるエンジニアが救いようの無いアホでどんなソースを書かせてもまともに書けず、自分達が作ったものを信頼もできないという悲惨な環境を除く) :-P

 



【過去の雑記】

メールアドレス収集ロボット対策の為メールアドレスはHP上に記載しておりません、
ソフト内のドキュメントには記載しておりますので、御用の方はそちらまでお願いします.
since 2003/10/04, Y.Ume/Tabo