Comment puis-je faire une exponentiation en clojure? Pour l'instant, je n'ai besoin que d'une exponentiation entière, mais la question vaut aussi pour les fractions.
récursivité classique (regardez ça, ça souffle pile)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
récursivité de la queue
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
fonctionnel
(defn exp [x n]
(reduce * (repeat n x)))
sournois (souffle également pile, mais pas si facilement)
(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))))))
bibliothèque
(require 'clojure.contrib.math)
Clojure a une fonction de puissance qui fonctionne bien: je recommanderais de l'utiliser plutôt que de passer par Java interop car il gère correctement tous les types de nombres à précision arbitraire Clojure.
Cela s'appelle expt
pour exponentiation plutôt que power
ou pow
ce qui explique peut-être pourquoi c'est un peu difficile à trouver ... de toute façon voici un petit exemple :
(use 'clojure.math.numeric-tower) ; as of Clojure 1.3
;; (use 'clojure.contrib.math) ; before Clojure 1.3
(expt 2 200)
=> 1606938044258990275541962092341162602522202993782792835301376
Vous pouvez utiliser les méthodes Java Math.pow
Ou BigInteger.pow
De Java:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Lorsque cette question a été posée à l'origine, clojure.contrib.math/expt était la fonction de bibliothèque officielle pour le faire. Depuis lors, il est passé à clojure.math.numeric-tower
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
Si vous avez vraiment besoin d'une fonction et non d'une méthode, vous pouvez simplement l'envelopper:
(defn pow [b e] (Math/pow b e))
Et dans cette fonction, vous pouvez le convertir en int
ou similaire. Les fonctions sont souvent plus utiles que les méthodes, car vous pouvez les passer en tant que paramètres à d'autres fonctions - dans ce cas, map
me vient à l'esprit.
Si vous devez vraiment éviter Java interop, vous pouvez écrire votre propre fonction de puissance. Par exemple, il s'agit d'une fonction simple:
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
Cela calcule la puissance de l'exposant entier (c'est-à-dire pas de racines).
De plus, si vous avez affaire à des nombres grands, vous pouvez utiliser BigInteger
au lieu de int
.
Et si vous avez affaire à des nombres très grands, vous voudrez peut-être les exprimer sous forme de listes de chiffres, et écrire vos propres fonctions arithmétiques pour les diffuser pendant qu'elles calculent le résultat et le transmettent à un autre courant.
Je pense que cela fonctionnerait aussi:
(defn expt [x pow] (apply * (repeat pow x)))
SICP inspiré version rapide itérative complète de la mise en œuvre "sournoise" ci-dessus.
(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)))
Utilisation clojure.math.numeric-tower
, anciennement 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))
Implémentation de la méthode "sneaky" avec récursivité de la queue et support de l'exposant négatif:
(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)))))))
Une simple doublure en utilisant réduire:
(defn pow [a b] (reduce * 1 (repeat b a)))
Essayer
(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)))))
pour une solution O (log n) récursive, si vous souhaitez l'implémenter vous-même (ne prend en charge que les entiers positifs). De toute évidence, la meilleure solution consiste à utiliser les fonctions de bibliothèque que d'autres ont indiquées.
Que diriez-vous de clojure.contrib.genric.math-functions
Il y a une fonction pow dans la bibliothèque clojure.contrib.generic.math-functions. C'est juste une macro pour Math.pow et c'est plus une façon "clojureish" d'appeler la fonction mathématique Java.