Comment puis-je faire de l'exponentiation en clojure? Pour l'instant, je n'ai besoin que d'exponentiation entière, mais la question vaut aussi pour les fractions.
Comment puis-je faire de l'exponentiation en clojure? Pour l'instant, je n'ai besoin que d'exponentiation entière, mais la question vaut aussi pour les fractions.
Réponses:
récursion classique (regardez ça, ça souffle pile)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
récursion de 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 la 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 d'alimentation qui fonctionne bien: je recommanderais de l'utiliser plutôt que de passer par l'interopérabilité Java car il gère correctement tous les types de nombres à précision arbitraire Clojure. Il se trouve dans l'espace de noms clojure.math.numeric-tower .
C'est appelé expt
à l' exponentiation plutôt que power
ou pow
ce qui explique peut-être pourquoi c'est un peu difficile à trouver ... en tout cas voici un petit exemple (note qui use
fonctionne mais mieux utiliser 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
Vous devez d'abord installer le package Java org.clojure.math.numeric-tower
pour rendre l'espace de noms Clojure clojure.math.numeric-tower
accessible!
Sur la ligne de commande:
$ lein new my-example-project
$ cd lein new my-example-project
Puis éditez project.clj
et ajoutez [org.clojure/math.numeric-tower "0.0.4"]
au vecteur de dépendances.
Démarrer un lein REPL (pas un clojure REPL)
$ lein repl
Maintenant:
(require '[clojure.math.numeric-tower :as math])
(math/expt 4 2)
;=> 16
ou
(require '[clojure.math.numeric-tower :as math :refer [expt]])
(expt 4 2)
;=> 16
Vous pouvez utiliser les méthodes Math.pow
ou Java BigInteger.pow
:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/pow
est plus compliquée math-pow
ou quel que soit le nom s'il y avait un équivalent clojure. S'il existe déjà une méthode java simple qui fait ce que vous voulez, il n'y a aucune raison de recréer la fonctionnalité dans clojure. L'interopérabilité Java n'est pas intrinsèquement nuisible.
Lorsque cette question a été posée à l'origine, clojure.contrib.math / expt était la fonction officielle de la bibliothèque pour ce faire. Depuis, il est passé à clojure.math.numeric-tower
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
(.pow 2M 100)
(Math/pow Math/E x)
fait l'affaire (en remplaçant Math/E
par la base de votre choix).
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 lancer 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, cela map
me vient à l'esprit.
Si vous avez vraiment besoin d'éviter l'interopérabilité Java, vous pouvez écrire votre propre fonction d'alimentation. Par exemple, c'est 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 pour l'exposant entier (c'est-à-dire pas de racines).
De plus, si vous avez affaire à de grands nombres, vous pouvez utiliser à la BigInteger
place de int
.
Et si vous avez affaire à de très grands nombres, vous voudrez peut-être les exprimer sous forme de listes de chiffres et écrire vos propres fonctions arithmétiques pour les parcourir au fur et à mesure qu'ils calculent le résultat et envoient le résultat vers un autre flux.
SICP a inspiré la version rapide itérative complète de l'implémentation «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)))
Utilisez clojure.math.numeric-tower
, autrefois 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 "sournoise" avec récursion de queue et supportant 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)))))))
Un simple one-liner 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 à la fin, si vous souhaitez l'implémenter vous-même (ne prend en charge que les entiers positifs). De toute évidence, la meilleure solution est d'utiliser les fonctions de bibliothèque que d'autres ont indiquées.
Que diriez-vous de clojure.contrib.genric.math-functions
Il existe une fonction pow dans la bibliothèque clojure.contrib.generic.math-functions. C'est juste une macro de Math.pow et c'est plus une façon "clojureish" d'appeler la fonction mathématique Java.