OCamlに整数のべき乗関数はありますか? **フロート専用です。ほとんど正確に見えますが、2のような精度エラーの可能性はありませんか?** 3. = 8.時々falseを返しますか?整数のべき乗のためのライブラリ関数はありますか?自分で書くこともできますが、効率の問題が出てきて、そのような機能がないのでびっくりします。
質問の浮動小数点部分について:OCamlは基礎となるシステムのpow()
関数を呼び出します。浮動小数点のべき乗は実装が難しい関数ですが、2. ** 3. = 8.
をtrue
に評価させるには、忠実である(つまり、1つに正確である 最後の場所の単位 )必要があります。なぜなら、8.0
は数学的に正しい結果の1つのULP内の唯一のfloat
だからです8。
すべての数学ライブラリは(*)忠実である必要があるため、この特定の例について心配する必要はありません。しかし 実際にはすべてではありません なので、心配するのは当然です。
63ビット以上の整数を使用している場合、指数の引数または結果をOCaml浮動小数点数(実際には9_007_199_254_740_993
または2を表すことができないIEEE 754倍精度数値)として正確に表すことができないことを心配するより良い理由があります。53 + 1)。この場合、浮動小数点のべき乗は、特定の実装の弱点のためではなく、その大きさの整数を正確に表すように設計されていないため、整数のべき乗の代わりにはなりません。
(*)この主題について読むためのもう1つの楽しい参考資料は、William Kahanによる「 対数が半分賢すぎる 」です。
標準ライブラリにはありません。ただし、自分で簡単に作成することも( 二乗による指数化 を使用して高速化することもできます)、これを提供する拡張ライブラリを再利用することもできます。 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を適用することにより、オーバーフローを回避する方法で実行できます。)
これは、2乗による指数化を使用する別の実装です(@gascheによって提供されるもののように)が、これは末尾再帰です。
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
上記のソリューションのより単純な定式化:
let pow =
let rec pow' a x n =
if n = 0 then a else pow' (a * (if n mod 2 = 0 then 1 else x)) (x * x) (n / 2) in
pow' 1
pow' a x n
はa
のx
をn
に計算します。