Как сделать возведение в степень в ближайшем будущем? - PullRequest
93 голосов
/ 20 февраля 2011

Как я могу делать возведения в степень в ближайшем будущем? Пока мне нужно только целочисленное возведение в степень, но вопрос касается и дробей.

Ответы [ 13 ]

128 голосов
/ 20 февраля 2011

классическая рекурсия (смотри, стек дует)

(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)
75 голосов
/ 22 февраля 2011

Clojure имеет мощную функцию, которая работает хорошо: я бы рекомендовал использовать ее, а не использовать взаимодействие с Java, поскольку он правильно обрабатывает все типы чисел Clojure с произвольной точностью.

Это называется expt для возведения в степень , а не power или pow, что, возможно, объясняет, почему его сложно найти ... в любом случае, вот небольшой пример:

(use 'clojure.math.numeric-tower)  ; as of Clojure 1.3
;; (use 'clojure.contrib.math)     ; before Clojure 1.3

(expt 2 200)
=> 1606938044258990275541962092341162602522202993782792835301376
52 голосов
/ 20 февраля 2011

Вы можете использовать методы Java Math.pow или BigInteger.pow:

(Math/pow base exponent)

(.pow (bigint base) exponent)
11 голосов
/ 20 февраля 2011

Когда этот вопрос первоначально задавался, clojure.contrib.math / expt была официальной библиотечной функцией для этого. С тех пор он перешел в clojure.math.numeric-tower

7 голосов
/ 27 октября 2013
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
5 голосов
/ 20 февраля 2011

Если вам действительно нужна функция, а не метод, вы можете просто обернуть ее:

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

, которая вычисляет мощность для целого показателя степени (т.е. без корней).

Кроме того, если вы имеете дело с large числа, вы можете использовать BigInteger вместо int.

И если вы имеете дело с очень большими числами, вы можете выразить их в виде списков цифр, инапишите свои собственные арифметические функции для потоковой передачи по ним, поскольку они вычисляют результат и выводят результат в некоторый другой поток.

4 голосов
/ 12 октября 2011

Я думаю, это тоже будет работать:

(defn expt [x pow] (apply * (repeat pow x)))
3 голосов
/ 10 апреля 2014

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)))
2 голосов
/ 11 апреля 2016

Простой однострочник, использующий уменьшение:

(defn pow [a b] (reduce * 1 (repeat b a)))
2 голосов
/ 06 февраля 2016

Реализация "подлого" метода с хвостовой рекурсией и поддержкой отрицательного показателя:

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