123

如何在clojure中进行幂运算?现在我只需要整数幂,但问题也适用于分数。

4

14 回答 14

153

经典递归(看这个,它会破坏堆栈)

(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)
于 2011-02-20T17:07:02.250 回答
82

Clojure 有一个运行良好的幂函数:我建议使用它而不是通过 Java 互操作,因为它可以正确处理所有 Clojure 任意精度数字类型。它位于命名空间clojure.math.numeric-tower中。

它被称为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 命名空间clojure.math.numeric-tower可访问!

在命令行上:

$ 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
于 2011-02-22T13:13:18.187 回答
69

您可以使用 java 的Math.powBigInteger.pow方法:

(Math/pow base exponent)

(.pow (bigdec base) exponent)
于 2011-02-20T12:38:22.093 回答
14

最初提出这个问题时,clojure.contrib.math/expt是执行此操作的官方库函数。从那时起,它已移至clojure.math.numeric-tower

于 2011-02-20T17:00:30.417 回答
9
user=> (.pow (BigInteger. "2") 10)
1024
user=> (.pow (BigInteger. "2") 100)
1267650600228229401496703205376
于 2013-10-27T13:54:21.413 回答
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)))

计算整数指数的幂(即没有根)。

此外,如果您要处理大量数字,您可能需要BigInteger使用int.

如果您正在处理非常大的数字,您可能希望将它们表示为数字列表,并编写自己的算术函数以在它们计算结果并将结果输出到其他流时对它们进行流式处理。

于 2011-02-20T14:00:46.907 回答
4

我认为这也可以:

(defn expt [x pow] (apply * (repeat pow x)))
于 2011-10-12T07:29:34.417 回答
4

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)))
于 2014-04-10T02:36:20.373 回答
2

一个使用 reduce 的简单单行:

(defn pow [a b] (reduce * 1 (repeat b a)))
于 2016-04-11T11:41:18.543 回答
2

使用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))
于 2015-07-30T18:03:24.020 回答
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)))))))
于 2016-02-06T13:53:00.427 回答
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) 解决方案,如果您想自己实现它(仅支持正整数)。显然,更好的解决方案是使用其他人指出的库函数。

于 2012-02-29T22:21:44.233 回答
1

我个人使用:

(defn pow [x n] (reduce *' (repeat n x)))

注意星号后面的撇号 (')。

适用于所有大小的整数。

注意:对于某些实现,这可能会有点慢。(时间(pow 2 200000))在我的系统上解决了 1.2 秒。

于 2021-10-28T22:07:32.133 回答
0

clojure.contrib.genric.math-functions 怎么样

clojure.contrib.generic.math-functions 库中有一个 pow 函数。它只是 Math.pow 的一个宏,更像是一种调用 Java 数学函数的“clojureish”方式。

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

于 2011-02-20T14:03:11.517 回答