web-dev-qa-db-ja.com

OCamlでの整数のべき乗

OCamlに整数のべき乗関数はありますか? **フロート専用です。ほとんど正確に見えますが、2のような精度エラーの可能性はありませんか?** 3. = 8.時々falseを返しますか?整数のべき乗のためのライブラリ関数はありますか?自分で書くこともできますが、効率の問題が出てきて、そのような機能がないのでびっくりします。

12
user2258552

質問の浮動小数点部分について: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による「 対数が半分賢すぎる 」です。

13
Pascal Cuoq

標準ライブラリにはありません。ただし、自分で簡単に作成することも( 二乗による指数化 を使用して高速化することもできます)、これを提供する拡張ライブラリを再利用することもできます。 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を適用することにより、オーバーフローを回避する方法で実行できます。)

25
gasche

これは、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
4

上記のソリューションのより単純な定式化:

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 naxnに計算します。

2
de Vilhena