Clojureで累乗を行うにはどうすればよいですか?今のところ、私は整数の累乗だけを必要としていますが、問題は分数にも当てはまります。
古典的な再帰(これを見て、スタックを爆破する)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
末尾再帰
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
機能的
(defn exp [x n]
(reduce * (repeat n x)))
卑劣な(スタックも吹きますが、それほど簡単ではありません)
(defn exp-s [x n]
(let [square (fn[x] (* x x))]
(cond (zero? n) 1
(even? n) (square (exp-s x (/ n 2)))
:else (* x (exp-s x (dec n))))))
としょうかん
(require 'clojure.contrib.math)
Clojureには、うまく機能するべき乗関数があります。すべてのClojureの任意精度の数値型を正しく処理するため、Java interopを経由するのではなく、これを使用することをお勧めします。
expt
やpower
ではなく、exponentiationの場合はpow
と呼ばれます。 :
(use 'clojure.math.numeric-tower) ; as of Clojure 1.3
;; (use 'clojure.contrib.math) ; before Clojure 1.3
(expt 2 200)
=> 1606938044258990275541962092341162602522202993782792835301376
JavaのMath.pow
またはBigInteger.pow
メソッドを使用できます。
(Math/pow base exponent)
(.pow (bigint base) exponent)
この質問が最初に尋ねられたとき、 clojure.contrib.math/expt はこれを行う公式のライブラリ関数でした。それ以来、 clojure.math.numeric-tower に移動しました
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
メソッドではなく関数が本当に必要な場合は、単純にラップできます。
(defn pow [b e] (Math/pow b e))
そして、この関数では、int
または同様のものにキャストできます。関数はパラメーターよりも別の関数に渡すことができるため、メソッドよりも便利です。この場合、map
が思い浮かびます。
Java interopを回避する必要がある場合は、独自のべき関数を作成できます。たとえば、これは単純な関数です。
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
これは、整数指数(つまり、根がない)のべき乗を計算します。
また、large数を扱う場合は、BigInteger
の代わりにint
を使用することもできます。
非常に大きい数を扱う場合は、それらを数字のリストとして表現し、独自の算術関数を記述して結果を計算し、結果を他の人に出力するストリーム。
これもうまくいくと思います:
(defn expt [x pow] (apply * (repeat pow x)))
SICPに触発された 上記の「スニーキー」実装の完全な反復高速バージョン。
(defn fast-expt-iter [b n]
(let [inner (fn [a b n]
(cond
(= n 0) a
(even? n) (recur a (* b b) (/ n 2))
:else (recur (* a b) b (- n 1))))
]
(inner 1 b n)))
つかいます - clojure.math.numeric-tower
、以前はclojure.contrib.math
。
(ns user
(:require [clojure.math.numeric-tower :as m]))
(defn- sqr
"Uses the numeric tower expt to square a number"
[x]
(m/expt x 2))
末尾再帰と負の指数をサポートする「卑劣な」メソッドの実装:
(defn exp
"exponent of x^n (int n only), with tail recursion and O(logn)"
[x n]
(if (< n 0)
(/ 1 (exp x (- n)))
(loop [acc 1
base x
pow n]
(if (= pow 0)
acc
(if (even? pow)
(recur acc (* base base) (/ pow 2))
(recur (* acc base) base (dec pow)))))))
Reduceを使用したシンプルなワンライナー:
(defn pow [a b] (reduce * 1 (repeat b a)))
試して
(defn pow [x n]
(loop [x x n n r 1]
(cond
(= n 0) r
(even? n) (recur (* x x) (/ n 2) r)
:else (recur x (dec n) (* r x)))))
末尾再帰O(log n)ソリューションの場合、自分で実装する場合(正の整数のみをサポート)。明らかに、より良い解決策は、他の人が指摘したライブラリ関数を使用することです。
Clojure.contrib.genric.math-functionsはどうですか
Clojure.contrib.generic.math-functionsライブラリにはpow関数があります。これはMath.powの単なるマクロであり、Java math関数を呼び出す「clojureish」な方法です。