如何在Mathematica中构造一个小于n的所有Fibonacci数的列表

时间:2012-12-22 21:31:02

标签: wolfram-mathematica

我想写一个Mathematica函数,它构造一个小于n的所有Fibonacci数的列表。此外,我希望尽可能优雅和功能(因此没有明确的循环)。

从概念上讲,我想获取自然数的无限列表,将Fib [n]映射到它上,然后在它们小于n时从该列表中获取元素。我怎样才能在Mathematica中做到这一点?

4 个答案:

答案 0 :(得分:3)

第一部分可以在 Mathematica 中相当容易地完成。下面,我提供了两个函数nextFibonacci,它提供的下一个斐波纳契数大于输入数(就像NextPrime)和fibonacciList,它提供了一个小于所有斐波那契数的列表。输入数字。

ClearAll[nextFibonacci, fibonacciList]
nextFibonacci[m_] := Fibonacci[
    Block[{n}, 
        NArgMax[{n, 1/Sqrt[5] (GoldenRatio^n - (-1)^n GoldenRatio^-n) <= m, n ∈ Integers}, n]
    ] + 1
]
nextFibonacci[1] := 2;

fibonacciList[m_] := Fibonacci@
    Range[0, Block[{n}, 
      NArgMax[{n, 1/Sqrt[5] (GoldenRatio^n - (-1)^n GoldenRatio^-n) < m, n ∈ Integers}, n]
    ]
]

现在你可以做以下事情:

nextfibonacci[15]
(* 21 *)

fibonacciList[50]
(* {0, 1, 1, 2, 3, 5, 8, 13, 21, 34} *)

第二部分虽然很棘手。您正在寻找的是Haskell类型的惰性求值,它只会在必要时进行评估(否则,您无法在内存中保留无限列表)。例如,像(在Haskell中):

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

然后允许你做

之类的事情
take 10 fibs
-- [0,1,1,2,3,5,8,13,21,34]

takeWhile (<100) fibs
-- [0,1,1,2,3,5,8,13,21,34,55,89]

不幸的是,没有内置的支持你想要的东西。但是,您可以扩展 Mathematica 以实现惰性样式列表,如this answer所示,它也是implemented as a package。既然你已经拥有了所需的所有部分,我会让你自己解决这个问题。

答案 1 :(得分:3)

如果您从GitHub抓取我的Lazy package,您的解决方案就像:

一样简单
Needs["Lazy`"]
LazySource[Fibonacci] ~TakeWhile~ ((# < 1000) &) // List

如果您希望稍微更实际地实现原始描述

  

从概念上讲,我想获取自然数的无限列表,将Fib [n]映射到它上,然后在它们小于n时从该列表中获取元素。

你可以这样做:

Needs["Lazy`"]
Fibonacci ~Map~ Lazy[Integers] ~TakeWhile~ ((# < 1000) &) // List

要证明这是完全懒惰的,请尝试前面的示例而不使用// List。你会看到它以(相当丑陋的)形式停止:

LazyList[First[ 
  LazyList[Fibonacci[First[LazyList[1, LazySource[#1 &, 2]]]], 
   Fibonacci /@ Rest[LazyList[1, LazySource[#1 &, 2]]]]], 
 TakeWhile[
  Rest[LazyList[Fibonacci[First[LazyList[1, LazySource[#1 &, 2]]]], 
    Fibonacci /@ Rest[LazyList[1, LazySource[#1 &, 2]]]]], #1 < 
    1000 &]]

这包含一个LazyList[]表达式,其第一个元素是您懒惰评估的表达式的第一个值,其第二个元素是如何继续扩展的说明。

改进

持续不断地调用Fibonacci[n]会有点低效,特别是当n开始变大时。实际上可以构造一个惰性生成器,它将在流式传输时计算Fibonacci序列的当前值:

Needs["Lazy`"]

LazyFibonacci[a_,b_]:=LazyList[a,LazyFibonacci[b,a+b]]
LazyFibonacci[]:=LazyFibonacci[1,1]

LazyFibonacci[] ~TakeWhile~ ((# < 1000)&) // List

最后,我们可以将其概括为一个更抽象的生成函数,该函数为累加器获取初始值,List Rule来计算下一步的累加器值以及{ {1}} List来计算当前累加器值的结果。

Rule

可以用它来生成Fibonacci序列,如下所示:

LazyGenerator[init_, step_, extract_] := 
 LazyList[Evaluate[init /. extract], 
  LazyGenerator[init /. step, step, extract]]

答案 2 :(得分:1)

好的,我希望我理解这个问题。但请注意,我不是纯数学专业,我是机械工程专业的学生。但这听起来很有趣。所以我查看了公式,这就是我现在能想到的。我必须跑,但如果有错误,请告诉我,我会解决它。

此操作要求n,然后列出小于n的所有斐波纳契数。没有循环可以找到少于n的Fibonacci数。它使用Reduce来求解小于n的斐波那契数。我在结果中发言,并且还在解决方案中提出了一个复杂的乘数。

然后使用Mathematica Fibonacci命令简单地创建所有这些数字的表格。因此,如果您输入n=20,则会列出1,1,2,3,5,8,13,依此类推。因为内存不足(我的电脑上只有8 GB的内存),我可以无限制地使用它。

我将n的限制设为500000随意编辑代码并进行更改。

Mathematica graphics

Manipulate[
 Module[{k, m}, 
  k = Floor@N[Assuming[Element[m, Integers] && m > 0, 
        Reduce[f[m] == n, m]][[2, 1, 2]] /. Complex[0, 2] -> 0];
  TableForm@Join[{{"#", "Fibonacci number" }}, 
    Table[{i, Fibonacci[i]}, {i, 1, k}]]
  ],

  {{n, 3, "n="}, 2, 500000, 1, Appearance -> "Labeled", ImageSize -> Small}, 
  SynchronousUpdating -> False, 
  ContentSize -> {200, 500}, Initialization :>
  {
   \[CurlyPhi][n_] := ((1 + Sqrt[5])/2)^n;
   \[Psi][n_] := -(1/\[CurlyPhi][n]);
   f[n_] := (\[CurlyPhi][n] - \[Psi][n])/Sqrt[5];
   }]

屏幕截图

Mathematica graphics

答案 3 :(得分:0)

Fibonacci数字Fk的索引k是k=Floor[Log[GoldenRatio,Fk]*Sqrt[5]+1/2]]https://en.wikipedia.org/wiki/Fibonacci_number。因此,小于或等于 n的斐波纳契数列表是

 FibList[n_Integer]:=Fibonacci[Range[Floor[Log[GoldenRatio,Sqrt[5]*n+1/2]]]]