私は最近パーセクでいくつかの仕事をしており、私のおもちゃの言語では、マルチベースの小数を表現可能にしたかったのです。 Parsecのソースを少し調べたところ、浮動小数点数パーサーの実装を見つけ、それをコピーして必要な変更を加えました。
だから私はこのコードが何をするのか、そして漠然とその理由を理解しています(私はまだ数学を完全に理解していませんが、要点を理解しています)。しかし、それはどこから来たのですか?これは文字列をfloatとintに変換するかなり賢い方法のようですが、このアルゴリズムに名前はありますか?それとも、私の知識の穴である基本的なものだけですか?パーセックの背後にいる人々はそれを考案しましたか?
これが最初の整数のコードです。
number' :: Integer -> Parser Integer
number' base =
do { digits <- many1 ( oneOf ( sigilRange base ))
; let n = foldl (\x d -> base * x + toInteger (convertDigit base d)) 0 digits
; seq n (return n)
}
したがって、ここでの基本的な考え方は、digits
に整数部分を表す文字列、つまり"192"
。 foldl
は、各桁を個別に数値に変換し、それを現在の合計にベースを掛けたものに加算します。つまり、最後に、各桁に正しい係数(合計)を掛けて、配置します。
小数部はさらに興味深いものです。
fraction' :: Integer -> Parser Double
fraction' base =
do { digits <- many1 ( oneOf ( sigilRange base ))
; let base' = fromIntegral base
; let f = foldr (\d x -> (x + fromIntegral (convertDigit base d))/base') 0.0 digits
; seq f (return f)
一般的な考え方は同じですが、foldr
になり、繰り返し除算を使用します。最初に加算してから分数を除算する理由がよくわかりませんが、最初に乗算してから全体を加算します。私はそれがうまくいくのを知っています、ただ理由を整理していません。
とにかく、私はそれを自分で解決するのはおかしいと感じます、それはそれを見て非常にシンプルで賢いです。このアルゴリズムの名前はありますか?おそらく、ループを使用した命令型バージョンはより身近なものでしょうか?
これは多項式を評価するための ホーナーの方法 のアプリケーションです。これは、基数がkの位置数値システムの数値abcdefが多項式a*x^5+b*x^4+...+f*x^0
であるという観察に基づいています。 x=k
で評価されました。
整数部分と小数部分の間に非対称性がある理由については、これは単に片側の指数0、1、2、...と-1 -2、...他の。
これは実際にはそれほど賢いことではなく、10進法がどのように機能するかの結果にすぎません。ループは折りたたみとして表現されるため、Haskellでは少し変わっているように見えるかもしれませんが、基本的なアルゴリズムは、これを回避できる最も簡単な方法です(数字の要素をハードコーディングすることを除いて、非常に多く、醜くて悪いです)方法)。
だから、本当にこのアルゴリズムに名前を付けるのに苦労した人はいないだろう。
私のHaskellは非常に錆びていますが、これからわかるように、これは文字列を浮動小数点数に変換する通常のすばやく簡単な方法です。迅速かつ簡単ですが、正確な数値が必要な量産コードには適していません。小数部の各桁の各除算により、仮数の最下位ビットの精度がIIRC、1/2失われる可能性があります。 UnixとWindowsのライブラリの内部については詳しくありませんが、1980年代にVAX/VMS数学ライブラリの一部のマイクロフィッシュを見た覚えがあります。また、正しく覚えていれば、ソフトウェアで実装された128ビット演算を使用しました。 (当時はハードウェアでサポートされていませんでした)計算の進行に伴う結果の正確さを保証します。