Clojureでべき乗を行う方法は?


106

Clojureでべき乗を実行するにはどうすればよいですか?現時点では、整数の累乗のみが必要ですが、問題は分数にも当てはまります。


18
Clojureを知らないが、好きになる傾向がある(Lisp、関数型プログラミング、および多くの便利なライブラリーを持っている)誰かとして、この単純な質問には非常に多くの答えがあることに失望しています-または全然尋ねられなければなりませんでした。累乗は、何も特別なことをしなくても、提供される基本的な機能の1つにすぎないと思いました。と聞いてよかったです。
Mars

1
そうですね、おそらくいくつかのバージョンがコアにあるはずです...しかし、私は多くの答えがまだ良い兆候であると思います。「実装への複数のパス」が、これらの多くが提供されていない理由のようです。ユーザーは、効率のために使用している関数の詳細を知っている必要があります。たとえば、(選択した回答で指摘されているように)スタックをブローする可能性のある方法もあれば、そうでない可能性の高い方法もあります。多分いくつかは怠惰で、いくつかは熱心です... Clojureでいくつかの注意を払う必要があるすべての詳細は、哲学のためにほとんどの重要なライブラリが提供されていない理由です
jm0

3
コアにexp関数だけがないのは、clojureの数値タワーが効率上の理由でひどく壊れているためだと思います。ですから、累乗とは、さまざまなことを意味します。(exp 2(exp 2 200))はどうあるべきですか?エラーまたは計算に時間がかかる巨大な整数?通常の浮動小数点expだけが必要な場合は、javaが組み込まれています。数値が実数のように機能するために最善を尽くし、コストを下げる言語が必要な場合は、clojureではなくスキームを使用します。
John Lawrence Aspden 2014

回答:


141

古典的な再帰(これを見て、スタックが爆破されます)

(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)

11
面白い答え!
Matt Fenwick、2011年


5
Clojure.contrib.mathが廃止され、参照Math.Numeric-タワー
アルバログラム

第二の提案(テール再帰)は、n <0のオーバーフロー整数有する
Pointo戦士

1
素晴らしい答え。マクロでそれを行う方法は次のとおりです。(defmacro exp [xn] `(*〜@(take n(repeat x))))
Daniel Szmulewicz '27

78

Clojureには、適切に機能するパワー関数があります。Clojureの任意精度の数値型をすべて正しく処理するため、Javaの相互運用機能ではなく、これを使用することをお勧めします。名前空間clojure.math.numeric-towerにあります。

それは呼ばれていますexptため、べき乗ではなく、powerまたはpow多分それは見つけることが少し難しいですなぜ...とにかく、ここで小さな例(なおだ説明しているuse作品が、より良い使用require):

(require '[clojure.math.numeric-tower :as math :refer [expt]])  ; as of Clojure 1.3
;; (use 'clojure.contrib.math)     ; before Clojure 1.3
(expt 2 200)
=> 1606938044258990275541962092341162602522202993782792835301376

パッケージのインストールに関する注意

org.clojure.math.numeric-towerClojure名前空間にclojure.math.numeric-towerアクセスできるようにするには、まずJavaパッケージをインストールする必要があります!

コマンドラインで:

$ lein new my-example-project
$ cd lein new my-example-project

次に、依存関係ベクトルを編集project.cljして追加[org.clojure/math.numeric-tower "0.0.4"]します。

レインREPLを開始する(clojure REPLではない)

$ lein repl

今:

(require '[clojure.math.numeric-tower :as math])
(math/expt 4 2)
;=> 16

または

(require '[clojure.math.numeric-tower :as math :refer [expt]])
(expt 4 2)
;=> 16

1
標準のClojureの一部ではないように見えるため、おそらく不明です。1.3.0こうすると、math.cljが見つからないというエラーが投げられます。
Brian Knoblauch、2011

9
1.3の時点では「clojure.math.numeric-tower」にあると思います(clojure.contribが個別のライブラリに分割されたため)
mikera '22

ユーザーの不満を和らげるために、「パッケージのインストールに関するリマインダー」を追加しました。
David Tonhofer

60

java Math.powまたはBigInteger.powメソッドを使用できます。

(Math/pow base exponent)

(.pow (bigint base) exponent)

+1。ただし、Javaライブラリと相互運用できることは承知しています。ただし、1)Math.powはdoubleで機能します。整数が必要です。例を挙げていただけますか?2)本当にsthに相互運用を使用する必要がありますか?力として単純?
Peter

ClojureはJavaライブラリの周りに構築されており、壊れていないものを修正しようとはせず、Math / powは正常に動作します。なぜdoubleやintegerを気にする必要があるのですか?このrichhickey.github.com/clojure-contrib/…を
DaVinci

1
@ピーター:1)パワーが大きすぎてダブルで正確に表現できない場合を除き、結果をintにキャストするだけで問題はありません。2)クロジュールに相当するものがあるとしたら、名前がどんなものになるかについて、文章Math/powがいかに複雑であるmath-powかわかりません。必要なことを実行する単純なJavaメソッドがすでにある場合は、clojureで機能を再作成する理由はありません。Javaの相互運用性は本質的に有害ではありません。
sepp2k

3
@Da vinci:奇妙な発言、それは独自の言語であり、Javaにある多くの関数(stringreverseなど)を持っています
Peter

4
正確なbigintegerパワーが必要な場合は、Clojureのclojure.contrib.math / exptを使用するほうがよいと思います。おそらく、ボンネットの下に同じですが、Javaの相互運用機能経由で行くよりもはるかに良くはありません.....
mikera

13

この質問が最初に尋ねられたとき、 clojure.contrib.math / exptがこれを行う公式のライブラリ関数でした。それ以来、それはclojure.math.numeric-towerに移動しました


Clojureの正確な計算(BigDecimal / BigIntegerなど)をすべて正しく処理するため、この回答の+1。
mikera


8
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376

6
また、あなたはこのためにリテラル表記を使用することができます(.pow 2M 100)
noisesmith

1
それらのタイプは異なります。user =>(タイプ2M)java.math.BigDecimal user =>(タイプ(BigInteger。 "2"))java.math.BigInteger
KIM Taegyoon 2013年

imo最高のソリューション、shower、既存のライブラリーの使用、bigintの処理を含みます。+1
Daniel Gruszczyk

私にとって(Math/pow Math/E x)はトリックMath/Eを行います(選択したベースで置き換えます)。
Zaz

6

メソッドではなく関数が本当に必要な場合は、単純にラップできます。

 (defn pow [b e] (Math/pow b e))

この関数では、それをにキャストできますint。多くの場合、関数は別の関数にパラメーターとして渡すことができるため、メソッドよりも便利です-この場合mapます。

Javaの相互運用を回避する必要がある場合は、独自のパワー関数を作成できます。たとえば、これは単純な関数です。

 (defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
   (if (neg? p) (/ 1 result) result)))

これは整数指数の指数を計算します(つまり、根がない)。

あなたが扱っている場合にも、大きな数字、あなたが使用することをお勧めしますBigInteger代わりにint

また、非常に大きな数値を扱う場合は、それらを数字のリストとして表現し、独自の算術関数を作成して、結果を計算し、結果を他のストリームに出力するときに、それらを介してストリーミングすることができます。


4

これもうまくいくと思います:

(defn expt [x pow] (apply * (repeat pow x)))

2 ^ 63で最大になるようです... defは2 ^ 200に対応していません
TJトラップ



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)))))))


1

試す

(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)ソリューションの場合、自分で実装したい場合(正の整数のみをサポート)。明らかに、より良い解決策は、他の人が指摘したライブラリー関数を使用することです。


0

clojure.contrib.genric.math-functionsはどうですか

clojure.contrib.generic.math-functionsライブラリには、pow関数があります。これは、Math.powの単なるマクロであり、Java数学関数を呼び出すためのより「奇妙な」方法です。

http://clojure.github.com/clojure-contrib/generic.math-functions-api.html#clojure.contrib.generic.math-functions/pow


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.