วิธีการยกกำลังใน clojure?


106

ฉันจะยกกำลังสองใน clojure ได้อย่างไร? ตอนนี้ฉันต้องการแค่การยกกำลังจำนวนเต็ม แต่คำถามก็เป็นเศษส่วนเช่นกัน


18
ในฐานะคนที่ไม่รู้จัก clojure แต่มีแนวโน้มที่จะชอบมัน (เป็นแฟนตัวยงของ lisps การเขียนโปรแกรมเชิงฟังก์ชันและมีไลบรารีที่มีประโยชน์มากมาย) ฉันผิดหวังที่คำถามง่ายๆนี้มีคำตอบมากมาย - หรือว่ามัน จะต้องถูกถามเลย ฉันคิดว่าการยกกำลังจะเป็นเพียงหนึ่งในฟังก์ชันพื้นฐานที่มีให้โดยไม่ต้องทำอะไรพิเศษเลย ฉันดีใจที่มีคนถาม
อังคาร

1
ใช่อาจมีบางเวอร์ชันที่ควรอยู่ในแกนหลัก ... แต่ฉันคิดว่าคำตอบมากมายยังคงเป็นสัญญาณที่ดี "หลายเส้นทางสู่การนำไปใช้" ดูเหมือนจะเป็นสาเหตุที่ไม่ได้ให้สิ่งเหล่านี้จำนวนมากผู้ใช้ควรทราบรายละเอียดของฟังก์ชันที่ใช้เพื่อประสิทธิภาพ ตัวอย่างเช่น (ตามที่ระบุไว้ในคำตอบที่เลือก) วิธีการบางอย่างอาจทำให้สแต็คระเบิด แต่วิธีอื่น ๆ มีโอกาสน้อยที่จะทำเช่นนั้น บางทีบางคนขี้เกียจบางคนกระตือรือร้น ... รายละเอียดทั้งหมดที่ต้องให้ความสนใจใน Clojure ซึ่งเป็นสาเหตุที่ฉันรู้สึกว่า libs ที่ไม่สำคัญที่สุดไม่ได้ให้ไว้เนื่องจากปรัชญา
jm0

3
ฉันคิดว่าเหตุผลที่ไม่มีเพียงฟังก์ชัน exp ในคอร์เป็นเพราะหอคอยตัวเลขของ clojure เสียด้วยเหตุผลด้านประสิทธิภาพ มีหลายสิ่งหลายอย่างที่คุณอาจหมายถึงโดยการยกกำลัง (exp 2 (exp 2 200)) ควรเป็นอย่างไร ข้อผิดพลาดหรือจำนวนเต็มจำนวนมากที่ต้องใช้อายุในการคำนวณ? หากคุณต้องการค่า exp แบบทศนิยมตามปกติก็จะมี java อยู่ในตัวหากคุณต้องการภาษาที่ตัวเลขทำได้ดีที่สุดเพื่อทำหน้าที่เหมือนจริงและแขวนค่าใช้จ่ายให้ใช้รูปแบบแทน clojure
John Lawrence Aspden

คำตอบ:


141

การเรียกซ้ำแบบคลาสสิก (ดูสิ่งนี้มันพัดกอง)

(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)

11
ตอบรับความบันเทิง!
Matt Fenwick

ดูวิธีแก้ปัญหาแบบลับๆซ้ำ ๆ ด้านล่างstackoverflow.com/a/22977674/231589
Karl Rosaen

5
Clojure.contrib.math เลิกใช้งานแล้วดูMath.Numeric-Tower
alvaro g

คำแนะนำที่สอง (tail recursive) มีจำนวนเต็มล้นสำหรับ n <0
Pointo Senshi

1
คำตอบที่ยอดเยี่ยม นี่คือวิธีการใช้มาโคร: (defmacro exp [xn] `(* ~ @ (ใช้ n (ซ้ำ x)))
Daniel Szmulewicz

78

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

1
อาจไม่เป็นที่รู้จักเนื่องจากดูเหมือนจะไม่เป็นส่วนหนึ่งของ Clojure มาตรฐาน 1.3.0 โยนข้อผิดพลาดเกี่ยวกับการไม่พบ math.clj เมื่อฉันพยายามทำด้วยวิธีนี้
Brian Knoblauch

9
ฉันคิดว่าตอนนี้อยู่ใน "clojure.math.numeric-tower" ตั้งแต่ 1.3 (เนื่องจาก clojure.contrib แยกออกเป็นแต่ละห้องสมุด)
mikera

เพิ่ม "การแจ้งเตือนเกี่ยวกับการติดตั้งแพ็กเกจ" เพื่อลดความยุ่งยากของผู้ใช้
David Tonhofer

60

คุณสามารถใช้ java Math.powหรือBigInteger.powวิธีการ:

(Math/pow base exponent)

(.pow (bigint base) exponent)

+1 แม้ว่าฉันรู้ว่าคุณสามารถทำงานร่วมกับ java libs ได้ อย่างไรก็ตาม 1) Math.pow ทำงานร่วมกับคู่ผสมฉันต้องการจำนวนเต็มคุณสามารถยกตัวอย่างได้หรือไม่? 2) คุณต้องใช้ interop สำหรับ sth จริงๆหรือไม่ ง่ายเหมือนพลัง?
ปีเตอร์

Clojure ถูกสร้างขึ้นรอบ ๆ ไลบรารี java มันไม่ได้พยายามแก้ไขสิ่งที่ไม่เสียและ Math / pow ทำงานได้ดี ทำไมคุณต้องดูแลคู่ผสมหรือจำนวนเต็ม? คุณยังสามารถใช้richhickey.github.com/clojure-contrib/…
DaVinci

1
@Peter: 1) เว้นแต่พลังของคุณจะใหญ่มากจนไม่สามารถแสดงเป็นคู่ผสมได้อย่างถูกต้องอีกต่อไปไม่มีปัญหากับการส่งผลลัพธ์เป็น int 2) ฉันไม่เห็นว่าการเขียนMath/powมีความซับซ้อนมากกว่าmath-powหรือชื่ออะไรถ้ามีค่าเทียบเท่า clojure หากมีเมธอด java ง่ายๆที่ทำในสิ่งที่คุณต้องการอยู่แล้วก็ไม่มีเหตุผลที่จะสร้างฟังก์ชันใหม่ใน clojure การทำงานร่วมกันของ Java ไม่เป็นอันตรายโดยเนื้อแท้
sepp2k

3
@Da vinci: คำพูดแปลก ๆ มันเป็นภาษาของตัวเองและมีฟังก์ชันมากมายที่อยู่ใน Java (เช่น stringreverse)
Peter

4
ฉันคิดว่าคุณใช้ clojure.contrib.math / expt ของ Clojure ได้ดีกว่าถ้าคุณต้องการพลังที่ยิ่งใหญ่ที่แม่นยำ อาจจะทำแบบเดียวกันภายใต้ประทุน แต่ดีกว่าการใช้งาน Java
Interop

13

เมื่อถามคำถามนี้ในตอนแรกclojure.contrib.math / exptเป็นฟังก์ชันไลบรารีอย่างเป็นทางการที่จะทำสิ่งนี้ ตั้งแต่นั้นมาก็ย้ายไปที่clojure.math.numeric-tower


+1 สำหรับคำตอบนี้เนื่องจากจัดการกับเลขคณิตที่แน่นอนของ Clojure (เช่น BigDecimal / BigInteger) ได้อย่างถูกต้อง
mikera

"หมายเหตุ - libs ที่มีส่วนร่วมได้ย้ายไปยัง repos แต่ละรายการภายใต้ Clojure org" ; ลิงค์นี้มีเพียงคำตอบเท่านั้นที่ทำให้เข้าใจผิด
Brad Koch

8
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376

6
นอกจากนี้คุณยังสามารถใช้สัญกรณ์ตามตัวอักษรสำหรับสิ่งนี้:(.pow 2M 100)
noisesmith

1
ประเภทของพวกเขาแตกต่างกัน user => (type 2M) java.math.BigDecimal user => (type (BigInteger. "2")) java.math.BigInteger
KIM Taegyoon

วิธีแก้ปัญหาที่ดีที่สุดของ imo การแสดงการใช้ไลบรารีที่มีอยู่และรวมถึงการจัดการ bigint +1
Daniel Gruszczyk

(Math/pow Math/E x)เคล็ดลับสำหรับฉัน(แทนที่Math/Eด้วยฐานที่คุณเลือก)
Zaz

6

หากคุณต้องการฟังก์ชั่นจริงๆและไม่ใช่วิธีการคุณสามารถห่อมันได้:

 (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)))

ที่คำนวณกำลังสำหรับเลขชี้กำลังจำนวนเต็ม (เช่นไม่มีราก)

นอกจากนี้ถ้าคุณจะจัดการกับขนาดใหญ่หมายเลขคุณอาจต้องการที่จะใช้แทนBigIntegerint

และถ้าคุณจะจัดการกับขนาดใหญ่มากตัวเลขคุณอาจต้องการที่จะแสดงให้พวกเขาเป็นรายชื่อของตัวเลขและเขียนฟังก์ชันเลขคณิตของคุณเองเพื่อสตรีมผ่านพวกเขาเป็นพวกเขาคำนวณผลและการส่งออกผลให้กระแสอื่น ๆ





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)))))))


1

ลอง

(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) แบบวนซ้ำหากคุณต้องการใช้งานด้วยตัวเอง (รองรับเฉพาะจำนวนเต็มบวกเท่านั้น) เห็นได้ชัดว่าทางออกที่ดีกว่าคือการใช้ฟังก์ชันไลบรารีที่ผู้อื่นชี้ให้เห็น


0

วิธีการเกี่ยวกับฟังก์ชัน clojure.contrib.genric.math

มีฟังก์ชัน pow ในไลบรารี clojure.contrib.generic.math-functions มันเป็นเพียงมาโครสำหรับ Math.pow และเป็นวิธีการเรียกฟังก์ชันคณิตศาสตร์ Java แบบ "clojureish" มากกว่า

http://clojure.github.com/clojure-contrib/generic.math-functions-api.html#clojure.contrib.generic.math-functions/pow


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.