Come posso eseguire l'elevazione a potenza in clojure? Per ora ho solo bisogno di un esponenziale intero, ma la domanda vale anche per le frazioni.
Come posso eseguire l'elevazione a potenza in clojure? Per ora ho solo bisogno di un esponenziale intero, ma la domanda vale anche per le frazioni.
Risposte:
ricorsione classica (guarda questo, fa saltare lo stack)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
ricorsione della coda
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
funzionale
(defn exp [x n]
(reduce * (repeat n x)))
subdolo (fa anche saltare lo stack, ma non così facilmente)
(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))))))
biblioteca
(require 'clojure.contrib.math)
Clojure ha una funzione di alimentazione che funziona bene: consiglierei di usarlo piuttosto che passare tramite l'interoperabilità Java poiché gestisce correttamente tutti i tipi di numeri a precisione arbitraria Clojure. È nello spazio dei nomi clojure.math.numeric-tower .
Si chiama expt
per l'elevamento a potenza , piuttosto che power
o pow
che forse spiega il motivo per cui è un po 'difficile da trovare ... in ogni caso, ecco un piccolo esempio (nota che use
funziona ma un uso migliore 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
È necessario prima installare il pacchetto Java org.clojure.math.numeric-tower
per rendere clojure.math.numeric-tower
accessibile lo spazio dei nomi Clojure !
Sulla riga di comando:
$ lein new my-example-project
$ cd lein new my-example-project
Quindi modifica project.clj
e aggiungi [org.clojure/math.numeric-tower "0.0.4"]
al vettore delle dipendenze.
Avvia un REPL lein (non un REPL clojure)
$ lein repl
Adesso:
(require '[clojure.math.numeric-tower :as math])
(math/expt 4 2)
;=> 16
o
(require '[clojure.math.numeric-tower :as math :refer [expt]])
(expt 4 2)
;=> 16
Puoi usare java Math.pow
o BigInteger.pow
metodi:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/pow
sia più complicato math-pow
o qualunque sia il nome se ci fosse un equivalente clojure. Se esiste già un semplice metodo java che fa quello che vuoi, non c'è motivo di ricreare la funzionalità in clojure. L'interoperabilità Java non è intrinsecamente dannosa.
Quando questa domanda è stata inizialmente posta, clojure.contrib.math / expt era la funzione di libreria ufficiale per farlo. Da allora, si è spostato in clojure.math.numeric-tower
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
(.pow 2M 100)
(Math/pow Math/E x)
fa il trucco (sostituire Math/E
con la base che preferisci).
Se hai davvero bisogno di una funzione e non di un metodo puoi semplicemente racchiuderlo:
(defn pow [b e] (Math/pow b e))
E in questa funzione puoi lanciarlo a int
o simili. Le funzioni sono spesso più utili dei metodi perché puoi passarle come parametri ad altre funzioni - in questo caso mi map
viene in mente.
Se hai davvero bisogno di evitare l'interoperabilità Java, puoi scrivere la tua funzione di alimentazione. Ad esempio, questa è una semplice funzione:
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
Questo calcola la potenza per l'esponente intero (cioè senza radici).
Inoltre, se hai a che fare con grandi numeri, potresti voler usare al BigInteger
posto di int
.
E se hai a che fare con numeri molto grandi , potresti esprimerli come elenchi di cifre e scrivere le tue funzioni aritmetiche per eseguire il flusso su di essi mentre calcolano il risultato e restituiscono il risultato a un altro flusso.
SICP ha ispirato la versione rapida e iterativa completa dell'implementazione "subdola" sopra.
(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)))
Usa clojure.math.numeric-tower
, in precedenza 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))
Implementazione del metodo "subdolo" con ricorsione in coda e supporto dell'esponente negativo:
(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)))))))
Un semplice one-liner con ridurre:
(defn pow [a b] (reduce * 1 (repeat b a)))
Provare
(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)))))
per una soluzione O (log n) ricorsiva in coda, se vuoi implementarla da solo (supporta solo numeri interi positivi). Ovviamente, la soluzione migliore è utilizzare le funzioni di libreria che altri hanno indicato.
Che ne dici di clojure.contrib.genric.math-functions
C'è una funzione pow nella libreria clojure.contrib.generic.math-functions. È solo una macro per Math.pow ed è più un modo "clojureish" di chiamare la funzione matematica Java.