web-dev-qa-db-fra.com

Comment faire l'exponentiation en clojure?

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.

96
Peter

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)
132
John Lawrence Aspden

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
75
mikera

Vous pouvez utiliser les méthodes Java Math.pow Ou BigInteger.pow De Java:

(Math/pow base exponent)

(.pow (bigint base) exponent)
52
sepp2k

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

11
amalloy
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
7
KIM Taegyoon

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.

5
Goran Jovic

Je pense que cela fonctionnerait aussi:

(defn expt [x pow] (apply * (repeat pow x)))
4
TJ Trapp

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)))
3
Karl Rosaen

Utilisation clojure.math.numeric-tower , anciennement clojure.contrib.math.


Documentation API


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

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

Une simple doublure en utilisant réduire:

(defn pow [a b] (reduce * 1 (repeat b a)))
2
Alan R. Soares

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.

1
Retief

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.

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

0
fido