¿Cómo puedo hacer exponenciación en clojure? Por ahora, solo necesito una exponenciación de números enteros, pero la pregunta también se aplica a las fracciones.
¿Cómo puedo hacer exponenciación en clojure? Por ahora, solo necesito una exponenciación de números enteros, pero la pregunta también se aplica a las fracciones.
Respuestas:
recursividad clásica (mira esto, sopla pila)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
recursividad de cola
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
funcional
(defn exp [x n]
(reduce * (repeat n x)))
furtivo (también se acumulan golpes, pero no tan fácilmente)
(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 tiene una función de potencia que funciona bien: recomendaría usar esto en lugar de usar la interoperabilidad de Java, ya que maneja todos los tipos de números de precisión arbitraria de Clojure correctamente. Está en el espacio de nombres clojure.math.numeric-tower .
Se llama exptpara exponenciación en lugar de power, o powlo que quizá explica por qué es un poco difícil de encontrar ... de todos modos aquí está un pequeño ejemplo (nota que usefunciona, pero un mejor usorequire ):
(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
Primero debe instalar el paquete de Java org.clojure.math.numeric-tower para que el espacio de nombres de Clojure sea clojure.math.numeric-toweraccesible!
En la línea de comando:
$ lein new my-example-project
$ cd lein new my-example-project
Entonces edita project.clj y agregue [org.clojure/math.numeric-tower "0.0.4"]al vector de dependencias.
Inicie un REPL lein (no un REPL clojure)
$ lein repl
Ahora:
(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
Puede utilizar los métodos Math.powo de Java BigInteger.pow:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/powes más complicada math-powo cualquiera que sea el nombre si hubiera un equivalente de clojure. Si ya existe un método java simple que hace lo que desea, no hay razón para recrear la funcionalidad en clojure. La interoperabilidad de Java no es intrínsecamente dañina.
Cuando se hizo esta pregunta originalmente, clojure.contrib.math / expt era la función oficial de la biblioteca para hacer esto. Desde entonces, se ha trasladado a clojure.math.numeric-tower
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
(.pow 2M 100)
(Math/pow Math/E x)hace el truco (reemplazando Math/Econ la base de su elección).
Si realmente necesita una función y no un método, simplemente puede ajustarlo:
(defn pow [b e] (Math/pow b e))
Y en esta función puedes enviarlo a into similar. Las funciones suelen ser más útiles que los métodos porque puede pasarlas como parámetros a otras funciones, en este casomap viene a la mente.
Si realmente necesita evitar la interoperabilidad de Java, puede escribir su propia función de potencia. Por ejemplo, esta es una función simple:
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
Eso calcula la potencia del exponente entero (es decir, sin raíces).
Además, si se trata de números grandes , es posible que desee utilizar en BigIntegerlugar deint .
Y si se trata de números muy grandes , es posible que desee expresarlos como listas de dígitos y escribir sus propias funciones aritméticas para transmitirlas a medida que calculan el resultado y envían el resultado a otra secuencia.
SICP inspiró la versión rápida iterativa completa de la implementación 'furtiva' anterior.
(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)))
Utilice clojure.math.numeric-tower, anteriormente 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))
Implementación del método "furtivo" con recursividad de cola y exponente negativo de apoyo:
(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 de una sola línea que usa reduce:
(defn pow [a b] (reduce * 1 (repeat b a)))
Tratar
(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)))))
para una solución O (log n) recursiva de cola, si desea implementarla usted mismo (solo admite enteros positivos). Obviamente, la mejor solución es utilizar las funciones de la biblioteca que otros han señalado.
¿Qué hay de clojure.contrib.genric.math-functions
Hay una función pow en la biblioteca clojure.contrib.generic.math-functions. Es solo una macro para Math.pow y es más una forma "clojureish" de llamar a la función matemática de Java.