Как сделать возведение в степень в clojure?

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

13 ответов


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

(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 interop, поскольку он правильно обрабатывает все типы чисел произвольной точности Clojure.

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

(use 'clojure.contrib.math)

(expt 2 200)
=> 1606938044258990275541962092341162602522202993782792835301376

начиная с Clojure 1.3, эта функция и другие связанные с ней функции математики переместились, поэтому вы надо сделать:

(use 'clojure.math.numeric-tower)

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

(Math/pow base exponent)

(.pow (bigint base) exponent)

когда этот вопрос был первоначально задан,http://clojure.github.com/clojure-contrib/math-api.html#clojure.contrib.math/expt где официальная библиотечная функция для этого жила. С тех пор он переехал в https://github.com/clojure/math.numeric-tower/blob/master/src/main/clojure/clojure/math/numeric_tower.clj#L80


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

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

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


документация по API


(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 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), если вы хотите реализовать его самостоятельно (поддерживает только положительные целые числа). Очевидно, что лучшим решением является использование библиотечных функций, на которые указывали другие.


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

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

Как насчет clojure.ВНО.genric.математические функции

в clojure есть функция pow.ВНО.родовой.библиотека математических функций. Это просто макрос для математики.pow и является более "clojureish" способом вызова математической функции Java.

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


простой ОДН-вкладыш используя уменьшает

(defn pow [a b] (reduce * 1 (repeat b a)))