Clojure'de üs alma işlemini nasıl yapabilirim? Şimdilik sadece tamsayı üssüne ihtiyacım var ama soru kesirler için de geçerli.
Clojure'de üs alma işlemini nasıl yapabilirim? Şimdilik sadece tamsayı üssüne ihtiyacım var ama soru kesirler için de geçerli.
Yanıtlar:
klasik özyineleme (bunu izle, yığını patlatır)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
kuyruk özyineleme
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
işlevsel
(defn exp [x n]
(reduce * (repeat n x)))
sinsi (aynı zamanda yığını da üfler, ancak o kadar kolay değil)
(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))))))
kütüphane
(require 'clojure.contrib.math)
Clojure'un iyi çalışan bir güç işlevi vardır: Tüm Clojure rasgele kesinlikli sayı türlerini doğru şekilde işlediği için Java ile birlikte çalışmak yerine bunu kullanmanızı öneririm. Clojure.math.numeric-tower ad alanında .
Bu expt, üs alma yerine powerya powda bulmanın neden biraz zor olduğunu açıklayabilir ... yine de işte küçük bir örnek ( useişe yaradığını ancak daha iyi kullanıldığını unutmayın 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 ad alanını clojure.math.numeric-towererişilebilir hale getirmek için önce Java paketini yüklemelisiniz !
Komut satırında:
$ lein new my-example-project
$ cd lein new my-example-project
Ardından , bağımlılıklar vektörünü düzenleyin project.cljve ekleyin [org.clojure/math.numeric-tower "0.0.4"].
Bir lein REPL başlatın (clojure REPL değil)
$ lein repl
Şimdi:
(require '[clojure.math.numeric-tower :as math])
(math/expt 4 2)
;=> 16
veya
(require '[clojure.math.numeric-tower :as math :refer [expt]])
(expt 4 2)
;=> 16
Java'nın Math.powveya BigInteger.powyöntemlerini kullanabilirsiniz :
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/powkadar karmaşık olduğunu math-powya da ad ne olursa olsun eşdeğeri bir taklit olsaydı anlamıyorum . İstediğinizi yapan basit bir java yöntemi zaten varsa, clojure'de işlevselliği yeniden oluşturmak için hiçbir neden yoktur. Java birlikte çalışması, doğası gereği zararlı değildir.
Bu soru ilk sorulduğunda clojure.contrib.math / expt bunu yapmak için resmi kütüphane işleviydi . O zamandan beri clojure.math.numeric-tower adresine taşındı
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
(.pow 2M 100)
(Math/pow Math/E x)için hile yapıyor ( Math/Eseçtiğiniz üs ile değiştirerek ).
Bir yönteme değil de gerçekten bir işleve ihtiyacınız varsa, onu kolayca sarmalayabilirsiniz:
(defn pow [b e] (Math/pow b e))
Ve bu işlevde onu intya da benzerine çevirebilirsiniz . İşlevler genellikle yöntemlerden daha kullanışlıdır çünkü bunları başka işlevlere parametre olarak aktarabilirsiniz - bu durumda mapaklıma geliyor.
Java birlikte çalışmasından gerçekten kaçınmanız gerekiyorsa, kendi güç işlevinizi yazabilirsiniz. Örneğin, bu basit bir işlevdir:
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
Bu, tamsayı üssü için gücü hesaplar (yani kök yok).
Ayrıca, büyük sayılarla uğraşıyorsanız , BigIntegeryerine kullanmak isteyebilirsiniz int.
Ve çok büyük sayılarla uğraşıyorsanız , bunları basamak listeleri olarak ifade etmek ve sonucu hesaplarken ve sonucu başka bir akışa çıkarırken üzerlerine akış yapmak için kendi aritmetik işlevlerinizi yazmak isteyebilirsiniz.
SICP , yukarıdaki 'sinsi' uygulamanın tam yinelemeli hızlı versiyonundan ilham almıştır .
(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-towerEskiden kullanın 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))
Kuyruk özyinelemeli ve negatif üs destekli "sinsi" yöntemin uygulanması:
(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)))))))
İndirgeme kullanan basit bir tek astar:
(defn pow [a b] (reduce * 1 (repeat b a)))
Deneyin
(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)))))
kuyruk özyinelemeli bir O (log n) çözümü için, bunu kendiniz uygulamak istiyorsanız (yalnızca pozitif tam sayıları destekler). Açıktır ki, daha iyi çözüm, başkalarının işaret ettiği kütüphane işlevlerini kullanmaktır.
Clojure.contrib.genric.math-functions nasıl
Clojure.contrib.generic.math-functions kütüphanesinde bir pow işlevi vardır. Bu sadece Math.pow için bir makrodur ve Java matematik fonksiyonunu çağırmanın daha "tıkanık" bir yoludur.