1

I tried to compute factorial through defmulti and defmethod.

(defmulti factorial identity)

(defmethod factorial 0 [_] 1)

(defmethod factorial :default [num]
  (* num (factorial (dec num))))

It works fine for small numbers

(-> 10 factorial) ;;3628800

(-> 2 factorial) ;; 2

it shows Integer Overflow Exception for factorial 40

(-> 40 factorial)

ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow

My curiosity is

How can we compute factorial for Big Numbers using defmulti and defmethod?

Srini
  • 823
  • 5
  • 10
  • 29
  • 1
    Possible duplicate of [Clojure - Calculate with big numbers](https://stackoverflow.com/questions/12826649/clojure-calculate-with-big-numbers) – cske Jul 19 '17 at 04:44
  • 1
    minor nagging: `(-> x factorial)` is way harder to read than just `(factorial x)`. Threading macros are great, but using them for everything is overkill – cfrick Jul 19 '17 at 06:17

2 Answers2

2

Clojure's implementation of number types builds on the host platform's number types. Your solution works when you define the arbitrary size flag N, because the underlying number type changes on the JVM.

(type 10)  ;=> java.lang.Long
(type 10N) ;=> clojure.lang.BigInt

clojure.lang.BigInt uses either java.math.BigInteger or a Java long as the underlying type, depending on the bit size of the number.

On a different host, the Javascript engine of a browser, both types are JavaScript's native Numbers. The factorial function gives a result up to 170 in ClojureScript. It does not throw when overflowing, but returns the JavaScript number value Infinity:

(factorial 170)  ; => 7.257415615307994e+306
(factorial 170N) ; => 7.257415615307994e+306
(factorial 171N) ; => Infinity

Update: This answer (pointed out by @cske) gives a neat solution to use the *' operator, which bumps up the number type in case it would overflow:

(defmethod factorial :default [num]
  (*' num (factorial (dec num))))

(factorial 40) ; => 815915283247897734345611269596115894272000000000N
Toni Vanhala
  • 1,352
  • 6
  • 16
0

I have solved it

(-> 40N factorial) ;;815915283247897734345611269596115894272000000000N
Srini
  • 823
  • 5
  • 10
  • 29