【问题标题】:How to calculate the 21! (21 factorial) in swift?如何计算21! (21阶乘)迅速?
【发布时间】:2016-06-02 20:33:24
【问题描述】:

我正在制作快速计算阶乘的函数。像这样

func factorial(factorialNumber: UInt64) -> UInt64 {
    if factorialNumber == 0 {
        return 1
    } else {
        return factorialNumber * factorial(factorialNumber - 1)
    }
}

let x = factorial(20)

这个函数可以计算到20岁。

我认为 factorial(21) 值大于 UINT64_MAX。

那么如何计算21! (21 阶乘)快速?

【问题讨论】:

  • 我认为这在纯 Swift 中是不可能的。至少不是微不足道的。我不知道任何可以开箱即用地计算这些数字的语言。
  • 我个人没用过,不过你可以试试github.com/kirsteins/BigInteger之类的库
  • 这可能很难看,但如果你将每次迭代的结果存储在一个字符串而不是 UIint 中,你可以像在纸上一样将它多重化。效率不高,BigInteger 库看起来更有用,但这也是一个选项。
  • 你需要阶乘做什么?如果它是方程的一部分(如在某些除法中),那么您可以在迭代步骤中计算方程,使子结果足够小以适应变量。另一种方法是使用 H,L 样式变量(每个数字 2 个变量)或使用某种 bigint 库。如果您选择 bigints,那么 Fast exact bigint factorial 可能会有所帮助
  • @dasdom:Python 也是。

标签: swift math


【解决方案1】:
func factorial(_ n: Int) -> Double {
  return (1...n).map(Double.init).reduce(1.0, *)
}
  1. (1...n):我们创建一个包含操作中涉及的所有数字的数组(即:[1, 2, 3, ...])。

  2. map(Double.init):我们从Int 更改为Double,因为我们可以用双精度表示比整数更大的数字(https://en.wikipedia.org/wiki/Double-precision_floating-point_format)。因此,我们现在将操作中涉及的所有数字的数组作为Doubles(即:[1.0, 2.0, 3.0, ...])。

  3. reduce(1.0, *):我们开始将 1.0 与数组中的第一个元素 (1.0*1.0 = 1.0) 相乘,然后将其结果与下一个元素 (1.0*2.0 = 2.0) 相乘,然后将其结果与下一个元素相乘(2.0*3.0 = 6.0) 等等。

第 2 步是避免溢出问题。

第 3 步是避免我们显式定义一个变量来跟踪部分结果。

【讨论】:

  • 如果你能在你的答案后面附上你的答案背后的逻辑评论,那就太好了
  • 你能在这背后提供一些解释吗?
  • 我添加了一些解释。
【解决方案2】:

无符号 64 位整数的最大值为 18,446,744,073,709,551,615。虽然21! = 51,090,942,171,709,440,000。对于这种情况,您需要一个 Big Integer 类型。我在 Swift 中发现了一个关于 Big Integer 的问题。该链接中有一个 Big Integer 库。

BigInteger equivalent in Swift?

【讨论】:

    【解决方案3】:

    您是否考虑过使用双倍?还是 NSDecimalNumber?

    同时递归调用相同的函数在性能方面确实很糟糕。

    如何使用循环:

    let value = number.intValue - 1
    
    var product = NSDecimalNumber(value: number.intValue)
    
    for i in (1...value).reversed() {
        product = product.multiplying(by: NSDecimalNumber(value: i))
    }
    

    【讨论】:

    • 次要问题:乘法方程的结果是它的“乘积”,而不是“总和”。
    【解决方案4】:

    这是一个接受任何符合Numeric 协议的类型的函数,它们都是内置数字类型。

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

    【讨论】:

      【解决方案5】:

      首先我们需要声明 double 类型的临时变量,以便它可以容纳数字的大小 然后我们创建一个接受 double 类型参数的函数然后我们检查数字是否等于 0 我们可以返回或不做任何我们有 if 条件所以我们可以打破函数的递归最后我们返回 temp 保持给定数字 func 的阶乘阶乘(x:Double) -> Double{

      var temp:Double = 1.0
      
      func factorial(x:Double) -> Double{
          if(x==0){
              //do nothing
          }else{
              factorial(x: x-1)
              temp *= x
          }
          return temp
      }
      
      factorial(x: 21.0)
      

      【讨论】:

        【解决方案6】:

        如果您愿意放弃精度,可以使用 Double 粗略计算高达 170 的阶乘:

        func factorial(_ n: Int) -> Double {
            if n == 0 {
                return 1
            }
            var a: Double = 1
            for i in 1...n {
                a *= Double(i)
            }
            return a
        }
        

        如果没有,请使用大整数库。

        【讨论】:

          【解决方案7】:
          func factoruial(_ num:Int) -> Int{
                  if num == 0 || num == 1{
                      return 1
                  }else{
                     return(num*factoruial(num - 1))
                 }
             }
          

          【讨论】:

          • 输入 21 -> 25321 Illegal instruction (core dumped)
          【解决方案8】:
          func factorial(a: Int) -> Int {
          
              return a == 1 ? a : a * factorial(a: a - 1)
          }
          
          print(factorial(a : 5))
          
          print(factorial(a: 9))
          

          【讨论】:

            【解决方案9】:

            使用递归来解决这个问题:

                func factorial(_ n: UInt) -> UInt {
                    return n < 2 ? 1 : n*factorial(n - 1)
                }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-12-17
              • 2015-04-19
              • 2022-01-25
              • 1970-01-01
              • 2011-04-16
              • 1970-01-01
              相关资源
              最近更新 更多