operator - ¿Cómo hacer exponenciación en clojure?
clojure sheet (13)
¿Cómo puedo hacer la exponenciación en clojure? Por ahora solo estoy necesitando un exponente entero, pero la pregunta también va para las fracciones.
¿Qué tal clojure.contrib.genric.math-functions
Hay una función pow en la biblioteca clojure.contrib.generic.math-functions. Es solo un macro de Math.pow y es más una forma "clojureish" de llamar a la función matemática de Java.
Clojure tiene una función de potencia que funciona bien: recomiendo usar esto en lugar de ir a través de la interoperabilidad de Java, ya que maneja correctamente todos los tipos de números de precisión arbitraria de Clojure.
Se llama expt
para exponenciación en lugar de power
o pow
que tal vez explique por qué es un poco difícil de encontrar ... de todos modos aquí hay un pequeño ejemplo:
(use ''clojure.contrib.math)
(expt 2 200)
=> 1606938044258990275541962092341162602522202993782792835301376
A partir de Clojure 1.3, esta función y otras funciones de matemáticas relacionadas se han movido, por lo que debe hacer:
(use ''clojure.math.numeric-tower)
Creo que esto también funcionaría:
(defn expt [x pow] (apply * (repeat pow x)))
Cuando se formuló originalmente esta pregunta, http://clojure.github.com/clojure-contrib/math-api.html#clojure.contrib.math/expt es donde vivía la función oficial de la biblioteca para hacer esto. Desde entonces, se ha movido a https://github.com/clojure/math.numeric-tower/blob/master/src/main/clojure/clojure/math/numeric_tower.clj#L80
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)))))))
Puedes usar los métodos Math.pow
o BigInteger.pow
java:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Si realmente necesita una función y no un método, simplemente puede envolverla:
(defn pow [b e] (Math/pow b e))
Y en esta función puedes convertirlo a int
o similar. Las funciones a menudo son más útiles que los métodos, ya que puede pasarlos como parámetros a otras funciones; en este caso, el map
viene a mi mente.
Si realmente necesita evitar la interoperabilidad de Java, puede escribir su propia función de encendido. 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 para el exponente entero (es decir, sin raíces).
Además, si se trata de números grandes , es posible que desee utilizar BigInteger
lugar de int
.
Y si está tratando con números muy grandes , puede expresarlos como listas de dígitos y escribir sus propias funciones aritméticas para transmitirlos a medida que calculan el resultado y emitir el resultado a alguna otra transmisión.
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 recursiva (log n), si desea implementarla usted mismo (solo admite enteros positivos). Obviamente, la mejor solución es usar las funciones de la biblioteca que otros han señalado.
Un simple trazador de líneas usando reduce
(defn pow [a b] (reduce * 1 (repeat b a)))
Utilice 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))
recursión clásica (mira esto, sopla pila)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
recursividad de la 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 sopla la pila, 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)
SICP inspiró la versión rápida iterativa completa de la implementación ''sneaky'' 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)))
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376