【问题标题】:Scala tail recursive method has an divide and remainder errorScala尾递归方法有一个除法和余数错误
【发布时间】:2018-10-13 16:55:18
【问题描述】:

我目前正在通过在 Scala 中编写尾递归来计算两个自然数的二项式系数。但是我的代码在除数方面有问题,整数除以 k 就像我所做的那样,因为这会给你一个非零余数,因此会引入舍入错误。那么谁能帮我弄清楚,如何解决它?

 def binom(n: Int, k: Int): Int = {
    require(0 <= k && k <= n)
    def binomtail(n: Int, k: Int, ac: Int): Int = {
      if (n == k || k == 0) ac
      else binomtail(n - 1, k - 1, (n*ac)/k)
    }
    binomtail(n,k,1)
  }

【问题讨论】:

    标签: scala debugging divide reminders binomial-coefficients


    【解决方案1】:

    一般来说,它成立:

    binom(n, k) = if (k == 0 || k == n) 1 else binom(n - 1, k - 1) * n / k
    

    如果你想在线性时间内计算它,那么你必须确保每个中间结果都是一个整数。现在,

    binom(n - k + 1, 1)
    

    当然是一个整数(它只是n - k + 1)。从这个数字开始,并将两个参数都加一,您可以通过以下中间步骤到达binom(n, k)

    binom(n - k + 1, 1)
    binom(n - k + 2, 2)
    ...
    binom(n - 2, k - 2)
    binom(n - 1, k - 1)
    binom(n, k)
    

    这意味着您必须以正确的顺序“累积”,从1k,而不是从k1 - 然后保证所有中间结果对应于实际二项式系数,因此是整数(不是分数)。这是尾递归函数的样子:

    def binom(n: Int, k: Int): Int = {
      require(0 <= k && k <= n)
      @annotation.tailrec 
      def binomtail(nIter: Int, kIter: Int, ac: Int): Int = {
        if (kIter > k) ac
        else binomtail(nIter + 1, kIter + 1, (nIter * ac) / kIter)
      }
      if (k == 0 || k == n) 1
      else binomtail(n - k + 1, 1, 1)
    }
    

    小视觉测试:

    val n = 12
    for (i <- 0 to n) {
      print(" " * ((n - i) * 2))
      for (j <- 0 to i) {
        printf(" %3d", binom(i, j))
      }
      println()
    }
    

    打印:

                               1
                             1   1
                           1   2   1
                         1   3   3   1
                       1   4   6   4   1
                     1   5  10  10   5   1
                   1   6  15  20  15   6   1
                 1   7  21  35  35  21   7   1
               1   8  28  56  70  56  28   8   1
             1   9  36  84 126 126  84  36   9   1
           1  10  45 120 210 252 210 120  45  10   1
         1  11  55 165 330 462 462 330 165  55  11   1
       1  12  66 220 495 792 924 792 495 220  66  12   1
    

    看起来不错,如果需要,可以将其与 this 进行比较。

    【讨论】:

      【解决方案2】:

      Andrey Tyukin 的出色示例在 n 较大时会失败,例如 binom(10000, 2),但可以很容易地适应使用 BigInt。

      def binom(n: Int, k: Int): BigInt = {
        require(0 <= k && k <= n)
        @annotation.tailrec 
        def binomtail(nIter: Int, kIter: Int, ac: BigInt): BigInt = {
          if (kIter > k) ac
          else binomtail(nIter + 1, kIter + 1, (nIter * ac) / kIter)
        }
        if (k == 0 || k == n) 1
        else binomtail(n - k + 1, 1, BigInt(1))
      }
      

      【讨论】:

        猜你喜欢
        • 2012-05-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-22
        • 2018-03-17
        • 1970-01-01
        • 2017-06-18
        相关资源
        最近更新 更多