¿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 expt
para exponenciación en lugar de power
, o pow
lo que quizá explica por qué es un poco difícil de encontrar ... de todos modos aquí está un pequeño ejemplo (nota que use
funciona, 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-tower
accesible!
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.pow
o de Java BigInteger.pow
:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/pow
es más complicada math-pow
o 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/E
con 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 int
o 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 BigInteger
lugar 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.