122 votes

Comment faire une exponentiation en clojure ?

Comment puis-je faire de l'exponentiation en clojure ? Pour l'instant, je n'ai besoin que de l'exponentiation des entiers, mais la question vaut aussi pour les fractions.

26 votes

En tant que personne qui ne connaît pas clojure, mais qui est prédisposée à l'aimer (étant un fan des lisps, de la programmation fonctionnelle, et ayant beaucoup de bibliothèques pratiques), je suis déçue que cette question simple ait tant de réponses - ou qu'elle doive être posée. J'aurais pensé que l'exponentiation serait juste une des fonctions de base fournies sans avoir à faire quoi que ce soit de spécial. Mais je suis content qu'elle ait été posée.

2 votes

Le "multiple path to implementation" semble être la raison pour laquelle beaucoup de ces choses ne sont pas fournies - l'utilisateur devrait connaître les détails de la fonction qu'il utilise pour des raisons d'efficacité. par exemple (comme indiqué dans la réponse choisie), certaines méthodes peuvent potentiellement faire sauter la pile, d'autres moins. par exemple (comme le souligne la réponse choisie), certaines façons de faire peuvent potentiellement faire sauter la pile, d'autres moins. peut-être que certains sont paresseux, d'autres enthousiastes... tous les détails doivent être pris en compte dans Clojure, c'est pourquoi je pense que la plupart des librairies non triviales ne sont pas fournies en raison de leur philosophie.

4 votes

Je pense que la raison pour laquelle il n'y a pas simplement une fonction exp dans le noyau est que la tour numérique de clojure est mal fichue pour des raisons d'efficacité. Il y a donc toutes sortes de choses différentes que l'on peut signifier par exponentiation. Que devrait être (exp 2 (exp 2 200)) ? Une erreur ou un énorme nombre entier qui prend un temps fou à calculer ? Si vous voulez simplement l'exp à virgule flottante habituelle, alors celle de Java est intégrée. Si vous voulez un langage où les nombres font de leur mieux pour agir comme les réels, et en supporter le coût, utilisez scheme au lieu de clojure.

153voto

John Lawrence Aspden Points 6295

Récursion classique (regardez ça, ça fait péter la 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 (fait également sauter la pile, mais pas aussi 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)

0 votes

Voir la version entièrement itérative de la solution sournoise ci-dessous stackoverflow.com/a/22977674/231589

7 votes

Clojure.contrib.math est maintenant déprécié, voir Tour numérique mathématique

1 votes

La deuxième suggestion (récursive en queue) présente un dépassement d'entier pour n < 0.

82voto

mikera Points 63056

Clojure possède une fonction de puissance qui fonctionne bien : Je vous recommande de l'utiliser plutôt que de passer par l'interopérabilité Java, car elle gère correctement tous les types de nombres à précision arbitraire de Clojure. Elle se trouve dans l'espace de noms clojure.math.numeric-tower .

Ça s'appelle expt para exponentiation plutôt que power o pow ce qui explique peut-être pourquoi il est un peu difficile à trouver ... de toute façon voici un petit exemple (notez que use fonctionne mais meilleure utilisation 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

Rappel sur l'installation des paquets

Vous devez d'abord installer le paquetage Java org.clojure.math.numeric-tower pour que 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 modifier project.clj et ajouter [org.clojure/math.numeric-tower "0.0.4"] au vecteur de dépendances.

Démarrer un REPL lein (pas un REPL clojure)

$ 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

1 votes

Probablement inconnu car il ne semble pas faire partie du standard Clojure. La version 1.3.0 affiche des erreurs indiquant qu'elle n'est pas en mesure de localiser le fichier math.clj lorsque j'essaie de le faire de cette manière.

9 votes

Je pense que c'est maintenant dans "clojure.math.numeric-tower" à partir de la version 1.3 (depuis que clojure.contrib a été divisé en bibliothèques individuelles).

0 votes

Ajout d'un "rappel sur l'installation des paquets" pour apaiser la frustration des utilisateurs.

69voto

sepp2k Points 157757

Vous pouvez utiliser l'outil de java Math.pow o BigInteger.pow méthodes :

(Math/pow base exponent)

(.pow (bigdec base) exponent)

1 votes

+1, bien que je sache que vous pouvez interopérer avec les librairies java ; cependant, 1) Math.pow fonctionne avec des doubles, j'ai besoin d'entiers, pouvez-vous donner un exemple ? 2) Faut-il vraiment utiliser l'interopérabilité pour des choses aussi simples que des puissances ?

0 votes

Clojure est construit autour des bibliothèques java, il ne tente pas de réparer ce qui n'est pas cassé et Math/pow fonctionne très bien. Pourquoi avez-vous besoin de vous préoccuper des doubles ou des entiers ? Vous pourriez également utiliser ceci richhickey.github.com/clojure-contrib/

1 votes

@Peter : 1) À moins que vos pouvoirs soient si grands qu'ils ne peuvent plus être représentés avec précision par des doubles, il n'y a vraiment aucun problème à simplement convertir le résultat en int. 2) Je ne vois pas comment écrire Math/pow est plus compliqué que math-pow ou quel que soit le nom qu'on lui donnerait s'il y avait un équivalent en 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é en clojure. L'interopérabilité Java n'est pas intrinsèquement nuisible.

14voto

amalloy Points 29125

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 lors, elle a été transférée à clojure.math.numeric-tower

0 votes

+1 pour cette réponse car elle gère correctement toute l'arithmétique exacte de Clojure (c'est-à-dire BigDecimal / BigInteger).

0 votes

9voto

KIM Taegyoon Points 196
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376

6 votes

Vous pouvez également utiliser la notation littérale pour cela : (.pow 2M 100)

1 votes

Leurs types sont différents. user=> (type 2M) java.math.BigDecimal user=> (type (BigInteger. "2")) java.math.BigInteger

0 votes

Imo meilleure solution, showr, utilisant les bibliothèques existantes, et incluant la gestion de bigint. +1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X