ฉันจะยกกำลังสองใน clojure ได้อย่างไร? ตอนนี้ฉันต้องการแค่การยกกำลังจำนวนเต็ม แต่คำถามก็เป็นเศษส่วนเช่นกัน
ฉันจะยกกำลังสองใน clojure ได้อย่างไร? ตอนนี้ฉันต้องการแค่การยกกำลังจำนวนเต็ม แต่คำถามก็เป็นเศษส่วนเช่นกัน
คำตอบ:
การเรียกซ้ำแบบคลาสสิก (ดูสิ่งนี้มันพัดกอง)
(defn exp [x n]
(if (zero? n) 1
(* x (exp x (dec n)))))
การเรียกซ้ำหาง
(defn exp [x n]
(loop [acc 1 n n]
(if (zero? n) acc
(recur (* x acc) (dec n)))))
การทำงาน
(defn exp [x n]
(reduce * (repeat n x)))
ส่อเสียด (ยังระเบิดกอง แต่ไม่ง่ายนัก)
(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))))))
ห้องสมุด
(require 'clojure.contrib.math)
Clojure มีฟังก์ชั่นการใช้พลังงานที่ทำงานได้ดี: ฉันขอแนะนำให้ใช้สิ่งนี้แทนที่จะใช้การทำงานร่วมกันของ Java เนื่องจากจัดการกับประเภทตัวเลขที่มีความแม่นยำโดยพลการของ Clojure ทั้งหมดอย่างถูกต้อง มันมีอยู่ใน namespace clojure.math.numeric หอ
เรียกว่าexpt
การยกกำลังมากกว่าpower
หรือpow
ซึ่งอาจอธิบายได้ว่าทำไมจึงหายากไปหน่อย ... อย่างไรก็ตามนี่คือตัวอย่างเล็ก ๆ (โปรดทราบว่าได้use
ผล แต่ใช้ได้ดีกว่า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
ก่อนอื่นคุณต้องติดตั้งแพ็คเกจ Java org.clojure.math.numeric-tower
เพื่อให้clojure.math.numeric-tower
สามารถเข้าถึงเนมสเปซ Clojure ได้!
ในบรรทัดคำสั่ง:
$ lein new my-example-project
$ cd lein new my-example-project
จากนั้นแก้ไขproject.clj
และเพิ่ม[org.clojure/math.numeric-tower "0.0.4"]
ในเวกเตอร์การอ้างอิง
เริ่ม Lein REPL (ไม่ใช่ clojure REPL)
$ lein repl
ตอนนี้:
(require '[clojure.math.numeric-tower :as math])
(math/expt 4 2)
;=> 16
หรือ
(require '[clojure.math.numeric-tower :as math :refer [expt]])
(expt 4 2)
;=> 16
คุณสามารถใช้ java Math.pow
หรือBigInteger.pow
วิธีการ:
(Math/pow base exponent)
(.pow (bigint base) exponent)
Math/pow
มีความซับซ้อนมากกว่าmath-pow
หรือชื่ออะไรถ้ามีค่าเทียบเท่า clojure หากมีเมธอด java ง่ายๆที่ทำในสิ่งที่คุณต้องการอยู่แล้วก็ไม่มีเหตุผลที่จะสร้างฟังก์ชันใหม่ใน clojure การทำงานร่วมกันของ Java ไม่เป็นอันตรายโดยเนื้อแท้
เมื่อถามคำถามนี้ในตอนแรกclojure.contrib.math / exptเป็นฟังก์ชันไลบรารีอย่างเป็นทางการที่จะทำสิ่งนี้ ตั้งแต่นั้นมาก็ย้ายไปที่clojure.math.numeric-tower
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
(.pow 2M 100)
(Math/pow Math/E x)
เคล็ดลับสำหรับฉัน(แทนที่Math/E
ด้วยฐานที่คุณเลือก)
หากคุณต้องการฟังก์ชั่นจริงๆและไม่ใช่วิธีการคุณสามารถห่อมันได้:
(defn pow [b e] (Math/pow b e))
และในฟังก์ชั่นนี้คุณสามารถแคสต์ให้int
หรือคล้ายกันได้ ฟังก์ชั่นมักจะมีประโยชน์มากกว่าที่วิธีการเพราะคุณสามารถส่งผ่านเป็นพารามิเตอร์ไปยังฟังก์ชันอื่น - ในกรณีนี้map
มาถึงฉัน
หากคุณต้องการหลีกเลี่ยงการทำงานร่วมกันของ Java จริงๆคุณสามารถเขียนฟังก์ชันกำลังของคุณเองได้ ตัวอย่างเช่นนี่เป็นฟังก์ชันง่ายๆ:
(defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
(if (neg? p) (/ 1 result) result)))
ที่คำนวณกำลังสำหรับเลขชี้กำลังจำนวนเต็ม (เช่นไม่มีราก)
นอกจากนี้ถ้าคุณจะจัดการกับขนาดใหญ่หมายเลขคุณอาจต้องการที่จะใช้แทนBigInteger
int
และถ้าคุณจะจัดการกับขนาดใหญ่มากตัวเลขคุณอาจต้องการที่จะแสดงให้พวกเขาเป็นรายชื่อของตัวเลขและเขียนฟังก์ชันเลขคณิตของคุณเองเพื่อสตรีมผ่านพวกเขาเป็นพวกเขาคำนวณผลและการส่งออกผลให้กระแสอื่น ๆ
ฉันคิดว่ามันก็ใช้ได้เช่นกัน:
(defn expt [x pow] (apply * (repeat pow x)))
SICP ได้สร้างแรงบันดาลใจให้กับการใช้งาน 'ส่อเสียด' เวอร์ชันรวดเร็วซ้ำ ๆ ด้านบน
(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)))
ใช้clojure.math.numeric-tower
เดิม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))
การใช้วิธีการ "ส่อเสียด" ด้วยการเรียกซ้ำหางและสนับสนุนเลขชี้กำลังเป็นลบ:
(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)))))))
ซับเดียวง่ายๆโดยใช้ลด:
(defn pow [a b] (reduce * 1 (repeat b a)))
ลอง
(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)))))
สำหรับโซลูชัน O (log n) แบบวนซ้ำหากคุณต้องการใช้งานด้วยตัวเอง (รองรับเฉพาะจำนวนเต็มบวกเท่านั้น) เห็นได้ชัดว่าทางออกที่ดีกว่าคือการใช้ฟังก์ชันไลบรารีที่ผู้อื่นชี้ให้เห็น
วิธีการเกี่ยวกับฟังก์ชัน clojure.contrib.genric.math
มีฟังก์ชัน pow ในไลบรารี clojure.contrib.generic.math-functions มันเป็นเพียงมาโครสำหรับ Math.pow และเป็นวิธีการเรียกฟังก์ชันคณิตศาสตร์ Java แบบ "clojureish" มากกว่า