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



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

698   13  

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

простой однострочный с помощью reduce

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

Comments

    Ничего не найдено.