Wie kann ich in Clojure potenzieren? Im Moment brauche ich nur eine ganzzahlige Potenzierung, aber die Frage gilt auch für Brüche.
Wie kann ich in Clojure potenzieren? Im Moment brauche ich nur eine ganzzahlige Potenzierung, aber die Frage gilt auch für Brüche.
Antworten:
klassische Rekursion (sehen Sie dies, es bläst Stapel)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
Schwanzrekursion
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
funktional
(defn exp [x n]
(reduce * (repeat n x)))
hinterhältig (auch Schläge stapeln, aber nicht so leicht)
(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))))))
Bibliothek
(require 'clojure.contrib.math)
Clojure verfügt über eine Power-Funktion, die gut funktioniert: Ich würde empfehlen, diese Funktion zu verwenden, anstatt über Java Interop zu arbeiten, da alle Clojure-Zahlentypen mit beliebiger Genauigkeit korrekt behandelt werden. Es befindet sich im Namespace clojure.math.numeric-Tower .
Es wird eher expt
zur Potenzierung aufgerufen als power
oder pow
was vielleicht erklärt, warum es ein bisschen schwer zu finden ist ... hier ist ein kleines Beispiel (Hinweis, der use
funktioniert, aber besser genutzt wird 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
Sie müssen zuerst das Java-Paket installieren org.clojure.math.numeric-tower
, um den Clojure-Namespace clojure.math.numeric-tower
zugänglich zu machen !
In der Befehlszeile:
$ lein new my-example-project
$ cd lein new my-example-project
Bearbeiten project.clj
Sie [org.clojure/math.numeric-tower "0.0.4"]
dann den Abhängigkeitsvektor und fügen Sie ihn hinzu .
Starten Sie eine Lein REPL (keine Clojure REPL)
$ lein repl
Jetzt:
(require '[clojure.math.numeric-tower :as math])
(math/expt 4 2)
;=> 16
oder
(require '[clojure.math.numeric-tower :as math :refer [expt]])
(expt 4 2)
;=> 16
Sie können Java Math.pow
oder BigInteger.pow
Methoden verwenden:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/pow
komplizierter das Schreiben ist als math-pow
oder wie auch immer der Name lauten würde, wenn es ein Clojure-Äquivalent gäbe. Wenn es bereits eine einfache Java-Methode gibt, die das tut, was Sie wollen, gibt es keinen Grund, die Funktionalität in clojure neu zu erstellen. Java Interop ist nicht von Natur aus schädlich.
Als diese Frage ursprünglich gestellt wurde, war clojure.contrib.math / expt die offizielle Bibliotheksfunktion, um dies zu tun. Seitdem ist es zu clojure.math.numeric-turm umgezogen
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
(.pow 2M 100)
(Math/pow Math/E x)
macht der Trick (durch Math/E
die Basis Ihrer Wahl ersetzen ).
Wenn Sie wirklich eine Funktion und keine Methode benötigen, können Sie sie einfach umbrechen:
(defn pow [b e] (Math/pow b e))
Und in dieser Funktion können Sie es auf int
oder ähnlich umwandeln. Funktionen sind oft nützlicher als Methoden, weil Sie sie als Parameter an andere Funktionen übergeben können - in diesem Fall map
fällt mir ein.
Wenn Sie Java Interop wirklich vermeiden müssen, können Sie Ihre eigene Power-Funktion schreiben. Dies ist beispielsweise eine einfache Funktion:
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
Das berechnet die Leistung für einen ganzzahligen Exponenten (dh keine Wurzeln).
Wenn Sie mit großen Zahlen arbeiten, möchten Sie möglicherweise BigInteger
stattdessen anstelle von verwenden int
.
Wenn Sie mit sehr großen Zahlen arbeiten, möchten Sie diese möglicherweise als Ziffernlisten ausdrücken und Ihre eigenen arithmetischen Funktionen schreiben, um sie zu streamen, während sie das Ergebnis berechnen und das Ergebnis an einen anderen Stream ausgeben.
SICP inspirierte die oben beschriebene vollständige iterative schnelle Version der 'hinterhältigen' Implementierung.
(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)))
Verwenden Sie clojure.math.numeric-tower
früher 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))
Implementierung der "hinterhältigen" Methode mit Schwanzrekursion und unterstützendem negativen Exponenten:
(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)))))))
Ein einfacher Einzeiler mit Reduce:
(defn pow [a b] (reduce * 1 (repeat b a)))
Versuchen
(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)))))
für eine schwanzrekursive O (log n) -Lösung, wenn Sie sie selbst implementieren möchten (unterstützt nur positive Ganzzahlen). Offensichtlich ist die bessere Lösung, die Bibliotheksfunktionen zu verwenden, auf die andere hingewiesen haben.
Wie wäre es mit clojure.contrib.genric.math-Funktionen
In der Bibliothek clojure.contrib.generic.math-functions gibt es eine pow-Funktion. Es ist nur ein Makro für Math.pow und eher eine "clojureische" Art, die Java-Mathematikfunktion aufzurufen.