【问题标题】:Go big.Int factorial with recursionGo big.Int 递归阶乘
【发布时间】:2012-06-30 00:38:39
【问题描述】:

我正在尝试实现这段代码:

func factorial(x int) (result int) {
  if x == 0 {
    result = 1;
  } else {
    result = x * factorial(x - 1);
  }
  return;
}

作为 big.Int 以使其对较大的 x 值有效。

以下是 fmt.Println(factorial(r)) 的返回值为 0

7的阶乘应该是5040?

关于我做错了什么有什么想法吗?

package main

import "fmt"
import "math/big"

func main() {
        fmt.Println("Hello, playground")

    //n := big.NewInt(40)
    r := big.NewInt(7)

    fmt.Println(factorial(r))

}

func factorial(n *big.Int) (result *big.Int) {
    //fmt.Println("n = ", n)
    b := big.NewInt(0)
    c := big.NewInt(1)

    if n.Cmp(b) == -1 {
        result = big.NewInt(1)
    }
    if n.Cmp(b) == 0 {
        result = big.NewInt(1)
    } else {
        // return n * factorial(n - 1);
        fmt.Println("n = ", n)
        result = n.Mul(n, factorial(n.Sub(n, c)))
    }
    return result
}

go 游乐场上的此代码:http://play.golang.org/p/yNlioSdxi4

【问题讨论】:

    标签: go


    【解决方案1】:

    转到包math.bigfunc (*Int) MulRange(a, b int64)。当第一个参数设置为 1 调用时,它会返回 b!:

    package main
    
    import (
        "fmt"
        "math/big"
    )
    
    func main() {
        x := new(big.Int)
        x.MulRange(1, 10)
        fmt.Println(x)
    }
    

    会产生

    3628800

    【讨论】:

    • 那是x.MulRange,不是x.mulRange
    • 这里的答案被低估了。大多数用法可能不需要 big.Int 作为阶乘方法的输入,仅作为返回类型(因为只有答案非常大)。如果是这种情况,MulRange 会更简单(更快)。
    【解决方案2】:

    在您的int 版本中,每个int 都是不同的。但是在您的big.Int 版本中,您实际上是在共享big.Int 值。所以当你说

    result = n.Mul(n, factorial(n.Sub(n, c)))
    

    表达式n.Sub(n, c) 实际上将0 存储回n,因此当评估n.Mul(n, ...) 时,您基本上是在执行0 * 1,因此您会返回0

    请记住,big.Int 操作的结果不只是返回它们的值,它们还将它们存储到接收器中。这就是为什么你会在 n.Mul(n, c) 这样的表达式中看到重复,例如为什么它再次将n 作为第一个参数。因为你也可以说result.Mul(n, c),你会得到相同的值,但它会存储在result而不是n

    为了避免这个问题,你的代码被重写了:

    func factorial(n *big.Int) (result *big.Int) {
        //fmt.Println("n = ", n)
        b := big.NewInt(0)
        c := big.NewInt(1)
    
        if n.Cmp(b) == -1 {
            result = big.NewInt(1)
        }
        if n.Cmp(b) == 0 {
            result = big.NewInt(1)
        } else {
            // return n * factorial(n - 1);
            fmt.Println("n = ", n)
            result = new(big.Int)
            result.Set(n)
            result.Mul(result, factorial(n.Sub(n, c)))
        }
        return
    }
    

    这是一个稍微更干净/优化的版本(我试图删除big.Ints 的无关分配):http://play.golang.org/p/feacvk4P4O

    【讨论】:

    • 谢谢!是的,这些 big.Int 操作的结果确实有点棘手。
    • @Greg:这是一个 much more compact 暗示,它跳过递归并直接进入 for 循环。
    【解决方案3】:

    例如,

    package main
    
    import (
        "fmt"
        "math/big"
    )
    
    func factorial(x *big.Int) *big.Int {
        n := big.NewInt(1)
        if x.Cmp(big.NewInt(0)) == 0 {
            return n
        }
        return n.Mul(x, factorial(n.Sub(x, n)))
    }
    
    func main() {
        r := big.NewInt(7)
        fmt.Println(factorial(r))
    }
    

    输出:

    5040
    

    【讨论】:

      【解决方案4】:

      非递归版本:

      func FactorialBig(n uint64) (r *big.Int) {
          //fmt.Println("n = ", n)
          one, bn := big.NewInt(1), new(big.Int).SetUint64(n)
          r = big.NewInt(1)
          if bn.Cmp(one) <= 0 {
              return
          }
          for i := big.NewInt(2); i.Cmp(bn) <= 0; i.Add(i, one) {
              r.Mul(r, i)
          }
          return
      }
      

      playground

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-28
        • 1970-01-01
        • 2015-04-19
        • 2019-08-06
        • 2019-07-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多