【问题标题】:Fibonacci numbers without using zipWith不使用 zipWith 的斐波那契数
【发布时间】:2021-05-16 16:33:15
【问题描述】:

我一直在尝试在不使用惰性zipwith 方法的情况下实现从 0 到 n 的斐波那契数列列表。到目前为止,我所拥有的是从 n 返回列表到 1 的代码。有什么办法可以更改此代码,使其完全从 0-n 返回列表?

例子:

fib_seq 4 = [3,2,1,1] 
-- output wanted: [1,1,2,3]

如果没有办法做我想让代码做的事情,有没有办法只返回斐波那契数字列表,再次输入一个数字 4 它将返回 [0, 1, 1, 2]。

fib_seq :: Int -> [Int]
fib_seq 0 = [0]
fib_seq 1 = [1]
fib_seq n = sum (take 2 (fib_seq (n-1))) : fib_seq (n-1)

【问题讨论】:

  • 最好使用 let,fib_seq2 n = let { fs = fib_seq2 (n-1) } in sum (take 2 fs) : fs。比较 fib_seq 30 的速度。

标签: haskell fibonacci


【解决方案1】:

您可以选择实现 fib 编号的另一种方法是使用辅助函数,然后使用它自己的函数来生成无限的 fib 编号列表,或者您可以使用 take 10 fibs 并且输出将是前 10 个 fib 数字。我的函数绝对不是用 zipWith 函数无限地计算 fib 数字的最快方法,但你在这里没有使用它,所以这是我在没有 zipWith 的情况下实现它的方法。

例如take 10 fibs 将返回:[0,1,1,2,3,5,8,13,21,34]

fib :: Int -> Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-1) + fib (n-2)   

fibs :: [Int]
fibs = (map fib [0..])

【讨论】:

  • 这就是我一直在寻找的,因为这让我可以选择是否需要无限列表,或者我想选择要打印的 fib 数字的数量,感谢您的帮助!!!
  • 没问题,很高兴这有帮助,这个问题中还有其他一些很好的答案,请确保您已经阅读并理解,我的版本调用较大的 fib 号码会非常慢程序需要进行的递归调用次数。
【解决方案2】:

感觉有点像作弊,但你可以像这样使用closed formula 来表示斐波那契数列:

fib n = (phi^n - psi^n) / sqrt 5
  where
    phi = (1 + sqrt 5) / 2
    psi = (1 - sqrt 5) / 2

fibSeq n = fib <$> [1 .. n]

否则 Haskell Wiki 有更多 implementation variants 可供选择。例如非常简洁

fibs = 0 : 1 : next fibs
  where
    next (a : t@(b:_)) = (a+b) : next t

【讨论】:

  • 封闭公式很早就会产生极差的精度。通过平方方法的矩阵求幂会更好。
  • 我们可能需要某种形式的任意固定精度数字才能使其工作,也许?我们可以将fib n 的大小近似为phi^n,因此我们提前知道所需的位数,并且为了安全起见,只需使用两倍的位数。问题是,这种事情的复杂性是什么。 :) @dfeuer
  • @WillNess,我不能告诉你,但似乎几乎可以肯定它不比平方乘法更好。
  • @dfeuer 我的感觉完全一样。 :)
  • 与矩阵形式有关,由于 φ 是代数数,您可以通过将其精确地表示为具有有理(或在本例中为整数)系数的多项式的隐式根来避免精度问题,即x² - x - 1,然后有一个非常漂亮的封闭式公式实现,这个注释框太小而无法包含。也不快哈哈
【解决方案3】:

如果您想让列表从 0 开始,您可以使用辅助函数,然后在您的 fib_seq 中使用此辅助函数(我建议您将其更改为 Camel 大小写,如 fibSeq,标准 Haskell 表示法)

好的,下面的函数fibSeq 7 将返回[0,1,1,2,3,5,8]:

fibHelp :: Int -> Int -> [Int]
fibHelp x y = x : (fibHelp y (x+y))

fibSeq :: Int -> [Int]
fibSeq n = take n (fibHelp 0 1)

【讨论】:

    【解决方案4】:

    通常情况下,您可以通过考虑更通用的版本来解决问题。

    假设我们想要以 两个 规定的初始值 a 和 b 开始的无限斐波那契列表。有一个明显的递归解决方案:

    $ ghci
    GHCi, version 8.8.4: https://www.haskell.org/ghc/  :? for help
     ...
     λ> 
     λ> aux_fib a b = a : (aux_fib b (a+b))
     λ> 
     λ> take 4 (aux_fib 1 1)
     [1,1,2,3]
     λ> 
    

    所以:

     λ> 
     λ> fib_seq n = take n (aux_fib 1 1)
     λ> 
     λ> fib_seq 4
     [1,1,2,3]
     λ> 
    

    注意:camel case在Haskell中被认为更惯用,所以更像auxFib和fibSeq。

    【讨论】:

      猜你喜欢
      • 2015-06-28
      • 1970-01-01
      • 2015-06-05
      • 2014-05-23
      • 2014-05-03
      • 1970-01-01
      • 2020-01-18
      相关资源
      最近更新 更多