2013-06-05 26 views
8

OCamlに整数累乗の関数がありますか? **は浮動小数点のみです。ほとんど正確であるように見えますが、精密エラーの可能性はありませんか?** 3. = 8. 8.時々falseを返しますか?整数累乗のためのライブラリ関数はありますか?私は自分自身を書くことができましたが、効率の問題がそこに入っています。また、そのような機能がまだなければ私は驚くでしょう。OCamlで整数累乗

答えて

10

についてあなたの質問の浮動小数点部分:OCamlは、基礎となるシステムのpow()関数を呼び出します。浮動小数点累乗は実装するのは難しい関数ですが、8.0は数学的に正しい結果の1つのULP内の唯一のものであるため、2. ** 3. = 8.trueとすることは忠実である必要があります(つまり、Unit in the Last Placeに正確です)。

すべての数学ライブラリは忠実である必要がありますので、この特定の例について心配する必要はありません。しかし、not all of them actually are、あなたは心配する権利です。あなたはOCamlは(実際にはIEEE 754倍精度数を浮動した引数または累乗の結果が正確に表現できないことを、63ビット整数またはより広いを使用している場合は心配する


より良い理由は、だろう9_007_199_254_740_993または2 +1を表すことはできません)。この場合、浮動小数点指数演算は整数の指数演算に代わるものであり、特定の実装の弱点ではありませんが、その整数を正確に表すように設計されていないためです。このテーマに読んで


(*)もう一つの楽しみの参照は、ウィリアム・カハンで「A Logarithm Too Clever by Half」です。

+0

引数が同じであれば、浮動小数点累乗は整数累乗と同じくらい速いのですか?また、浮動小数点累乗は、-2^30≦a^b <2^30の整数a、bについては真実でなければならない、または私の特定の例の2 3や8? – user2258552

+0

@ user2258552速度に関して:浮動小数点指数は、おそらく書き込まれた整数型のものよりも遅いでしょう。 "should"の意味について:忠実な初等関数は、その定義域を渡って1つのULPに対して正確です。すべてのlibmsは忠実でなければなりません。なぜなら、計算コストと正確さとの間で合理的な妥協点があるからです。精度は0.5です。テーブルメーカーのジレンマのために、すべてのlibmsを期待するのは少し難しいですが、1 ULPまでの精度は妥当なコストで達成できます。 (しかし、pow()もまた最も難しい初等関数の1つです) –

+0

スピードに関して:これを踏まえて、標準ライブラリに整数累乗関数を含まないことは実際にはほとんど意味がありません... – user2258552

19

標準ライブラリにはありません。しかし、自分で簡単に書くことができます(速くなるようにexponentiation by squaringを使用)、またはこれを提供する拡張ライブラリを再利用します。 Batteriesには、Int.powです。以下は

提案実装です:

let rec pow a = function 
    | 0 -> 1 
    | 1 -> a 
    | n -> 
    let b = pow a (n/2) in 
    b * b * (if n mod 2 = 0 then 1 else a) 

あなたは非常に大きな数字を操作しているので、オーバーフローの危険性がある場合、あなたはおそらく、すべての種類を提供している、などZarithとして大きな整数ライブラリを使用する必要があります累乗関数の

は、(あなたが(a^n) mod pを計算する、「べき乗剰余」を必要とすることができ、これは、上記機能pow、例えば、中間計算にMODを適用することにより、オーバーフローを回避する方法で行うことができる。)

+3

グレート答えは別の実装です。残念ながら、私は1つの最良の答えを選ぶことしかできませんでした:/。また、これは常に整数累乗を実装する最速の方法であるとは私は確信していません。実際には、これらの線に沿ってプロジェクトオイラーの質問(私はまだ解決していません)があると思います。私は本当に整数のべき乗が標準ライブラリに追加されるべきだと思います。これ以上効率的ではないとしても(私は確信していませんが)、それは必要とする変換の一般的なものであり、浮動小数点からの変換と矛盾は厄介です。もちろん、ライブラリを読み込むのは難しいことではありませんが、標準ではない理由はありません。 – user2258552

+2

一般的な場合に整数実装を実装する方法の良いアイデアがある場合は、実装を提案することを自由にしてください。 – gasche

+0

@ user2258552整数累乗が非常に一般的であるという前提には同意できません。実際には、ほとんどの場合、小さな固定指数で作業するか、gascheが示唆するように任意の精度演算を必要とします。 TL; DR:固定精度intで整数累乗が必要であると信じて、任意の精度の算術ライブラリが必要であることを理解してください。 –

3

ここで(@gascheが提供するもののような)乗で累乗を使用しますが、この1つは末尾再帰

let is_even n = 
    n mod 2 = 0 

(* https://en.wikipedia.org/wiki/Exponentiation_by_squaring *) 
let pow base exponent = 
    if exponent < 0 then invalid_arg "exponent can not be negative" else 
    let rec aux accumulator base = function 
    | 0 -> accumulator 
    | 1 -> base * accumulator 
    | e when is_even e -> aux accumulator (base * base) (e/2) 
    | e -> aux (base * accumulator) (base * base) ((e - 1)/2) in 
    aux 1 base exponent 
+1

テール - 再帰性は入力の関数対数には関係しません。どのようにスタックを吹くことができますか?もちろん、tail-recursivityがコードについて興味深いことを明らかにする異なる視点を与えたり、読みやすくすることができれば、それはまだ面白いかもしれません。 – gasche

+0

あなたは正しいです。このコードは、63または31ビットの整数には意味がありません。このようなアルゴリズムは、任意精度の数値には意味をなさないでしょう。 – Halst

+0

"面白いことが明らかになりました":あなたのコメント、@ gasche。 :-) – Mars

関連する問題