How to calculate the 21! (21 factorial) in swift?

Did you think about using a double perhaps? Or NSDecimalNumber?

Also calling the same function recursively is really bad performance wise.

How about using a loop:

let value = number.intValue - 1

var product = NSDecimalNumber(value: number.intValue)

for i in (1...value).reversed() {
    product = product.multiplying(by: NSDecimalNumber(value: i))
}

func factorial(_ n: Int) -> Double {
  return (1...n).map(Double.init).reduce(1.0, *)
}
  1. (1...n): We create an array of all the numbers that are involved in the operation (i.e: [1, 2, 3, ...]).

  2. map(Double.init): We change from Int to Double because we can represent bigger numbers with Doubles than with Ints (https://en.wikipedia.org/wiki/Double-precision_floating-point_format). So, we now have the array of all the numbers that are involved in the operation as Doubles (i.e: [1.0, 2.0, 3.0, ...]).

  3. reduce(1.0, *): We start multiplying 1.0 with the first element in the array (1.0*1.0 = 1.0), then the result of that with the next one (1.0*2.0 = 2.0), then the result of that with the next one (2.0*3.0 = 6.0), and so on.

Step 2 is to avoid the overflow issue.

Step 3 is to save us from explicitly defining a variable for keeping track of the partial results.


Here's a function that accepts any type that conforms to the Numeric protocol, which are all builtin number types.

func factorial<N: Numeric>(_ x: N) -> N {
    x == 0 ? 1 : x * factorial(x - 1)
}

Unsigned 64 bit integer has a maximum value of 18,446,744,073,709,551,615. While 21! = 51,090,942,171,709,440,000. For this kind of case, you need a Big Integer type. I found a question about Big Integer in Swift. There's a library for Big Integer in that link.

BigInteger equivalent in Swift?

Tags:

Math

Swift