클로저에서 지수화하는 방법은 무엇입니까?


106

클로저에서 지수화하려면 어떻게해야합니까? 지금은 정수 지수화 만 필요하지만 문제는 분수에도 적용됩니다.


18
clojure를 모르지만 그것을 좋아하는 경향이있는 사람으로서 (입술, 함수형 프로그래밍의 팬이고, 편리한 라이브러리를 많이 가지고있는),이 간단한 질문에 너무 많은 답변이 있거나 전혀 질문을 받아야했습니다. 나는 지수 화가 특별한 일을 전혀하지 않고도 제공되는 기본 기능 중 하나 일 것이라고 생각했을 것입니다. 그래도 질문을 받아 기쁩니다.
화성

1
글쎄, 아마도 그것의 일부 버전이 핵심에 있어야하지만 많은 답변이 여전히 좋은 징조라고 생각합니다. "다중 구현 경로"는 이러한 것들이 많이 제공되지 않는 이유 인 것 같습니다. 사용자는 효율성을 위해 사용중인 기능의 세부 사항을 알아야합니다. 예를 들어 (선택한 답변에서 지적했듯이) 어떤 방법은 잠재적으로 스택을 날려 버리고 다른 방법은 그렇게 할 가능성이 적습니다. 아마도 일부는 게으르고, 일부는 열심입니다 ... Clojure에서주의를 기울여야 할 모든 세부 사항은 철학 때문에 대부분의 사소하지 않은 라이브러리가 제공되지 않는다고 생각하는 이유입니다
jm0

3
핵심에 exp 함수가없는 이유는 clojure의 숫자 타워가 효율성 때문에 심하게 손상 되었기 때문이라고 생각합니다. 따라서 지수화로 의미 할 수있는 모든 종류의 다른 것들이 있습니다. (exp 2 (exp 2 200))은 무엇이어야합니까? 계산하는 데 시간이 걸리는 오류 또는 거대한 정수? 일반적인 부동 소수점 exp를 원하면 자바가 내장되어 있습니다. 숫자가 실수처럼 행동하고 비용을 걸기 위해 최선을 다하는 언어를 원한다면 clojure 대신 scheme을 사용하십시오.
John Lawrence Aspden 2014

답변:


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 2011


5
Clojure.contrib.math는 이제 더 이상 사용되지 않습니다. Math.Numeric-Tower
alvaro g를

두 번째 제안 (꼬리 재귀) N <0에 대한 정수 오버플로를 갖는다
Pointo 센시에게

1
환상적인 대답입니다. 다음은 매크로와 함께 할 방법은 다음과 같습니다 (defmacro 특급 [XN]`(* ~ @ (테이크 N (반복 X))))
다니엘 Szmulewicz

78

Clojure에는 잘 작동하는 강력한 기능이 있습니다. 모든 Clojure 임의 정밀도 숫자 유형을 올바르게 처리하므로 Java interop을 사용하는 것보다 이것을 사용하는 것이 좋습니다. 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

패키지 설치에 대한 알림

org.clojure.math.numeric-towerClojure 네임 스페이스에 clojure.math.numeric-tower액세스 할 수 있도록 하려면 먼저 Java 패키지 를 설치해야합니다 !

명령 줄에서 :

$ lein new my-example-project
$ cd lein new my-example-project

그런 다음 종속성 벡터를 편집 project.clj하고 추가 [org.clojure/math.numeric-tower "0.0.4"]합니다.

lein REPL 시작 (클로저 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 2011

9
1.3 현재 "clojure.math.numeric-tower"에있는 것 같습니다 (clojure.contrib이 개별 라이브러리로 분리 되었기 때문에)
mikera dec

사용자의 불만을 덜기 위해 "패키지 설치에 대한 알림"을 ​​추가했습니다.
David Tonhofer

60

Java Math.pow또는 BigInteger.pow메소드를 사용할 수 있습니다 .

(Math/pow base exponent)

(.pow (bigint base) exponent)

+1, Java libs와 상호 운용 할 수 있다는 것을 알고 있습니다. 그러나 1) Math.pow는 복식으로 작동합니다. 정수가 필요합니다. 예를 들어 줄 수 있습니까? 2) 정말 sth에 interop을 사용해야합니까? 힘만큼 간단합니까?
Peter

Clojure는 자바 라이브러리를 중심으로 구축되었으며, 손상되지 않은 것을 수정하려고 시도하지 않으며 Math / pow가 잘 작동합니다. 왜 두 배나 정수를 신경 써야합니까? 이 richhickey.github.com/clojure-contrib/…을
DaVinci

1
@Peter : 1) 당신의 힘이 너무 커서 더 이상 두 배로 정확하게 표현할 수없는 경우가 아니라면 결과를 int로 캐스트하는 데는 문제가 없습니다. 2) 클로저에 상응하는 이름이 있다면 글쓰기 Math/powmath-pow이름이 무엇이든간에 얼마나 복잡한 지 모르겠습니다 . 원하는 작업을 수행하는 간단한 Java 메서드가 이미있는 경우 clojure에서 기능을 다시 만들 이유가 없습니다. Java interop은 본질적으로 해롭지 않습니다.
sepp2k

3
@Da vinci : 이상한 발언, 자체 언어이며 Java에있는 많은 기능이 있습니다 (예 : stringreverse)
Peter

4
정확한 biginteger 힘을 원한다면 Clojure의 clojure.contrib.math / expt를 사용하는 것이 더 낫다고 생각합니다. 아마 ..... 자바 상호 운용성을 통해가는 것보다 후드하지만 훨씬 좋네요에서 같은 일
mikera

13

이 질문이 처음에 제기되었을 때 clojure.contrib.math / expt가이 를 수행하는 공식 라이브러리 기능이었습니다. 그 이후로 clojure.math.numeric-tower 로 이동했습니다.


모든 Clojure 정확한 (즉, BigDecimal / BigInteger) 산술을 올바르게 처리하므로이 답변에 +1.
mikera

"참고-contrib 라이브러리가 Clojure 조직 아래의 개별 저장소로 이동했습니다 . " ; 이 링크 전용 답변은 이제 오해의 소지가 있습니다.
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 최고의 솔루션, showr, 기존 라이브러리 사용 및 bigint 처리 포함. 한
다니엘 Gruszczyk

나를 (Math/pow Math/E x)위해 트릭 Math/E을 수행합니다 (선택한 기반으로 대체 ).
Zaz 2015

6

메서드가 아니라 함수가 정말로 필요한 경우 간단히 래핑 할 수 있습니다.

 (defn pow [b e] (Math/pow b e))

그리고이 함수에서 당신은 그것을 int또는 유사하게 캐스팅 할 수 있습니다 . 함수는 다른 함수에 매개 변수로 전달할 수 있기 때문에 메서드보다 종종 더 유용합니다 map.

Java interop을 피해야하는 경우 고유 한 power 함수를 작성할 수 있습니다. 예를 들어 다음은 간단한 함수입니다.

 (defn pow [n p] (let [result (apply * (take (abs p) (cycle [n])))]
   (if (neg? p) (/ 1 result) result)))

정수 지수 (즉, 근 없음)에 대한 검정력을 계산합니다.

또한 많은 수를 처리 하는 경우 BigInteger대신 을 사용할 수 있습니다 int.

그리고 매우 큰 숫자를 처리하는 경우 숫자 목록으로 표현하고 결과를 계산하고 결과를 다른 스트림에 출력 할 때 자신의 산술 함수를 작성하여 스트리밍 할 수 있습니다.


4

나는 이것도 작동 할 것이라고 생각한다.

(defn expt [x pow] (apply * (repeat pow x)))

하지만 2 ^ 200의 고화질 할 수 없다 ... 2 ^ 63에서 최대 밖으로 보인다
TJ 트랩

4

SICP 는 위의 'sneaky'구현의 전체 반복 빠른 버전에 영감을주었습니다 .

(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

꼬리 재귀를 사용하고 음의 지수를 지원하는 "sneaky"방법 구현 :

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


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.