【算法】斐波那契数列与台风的故事

算法,数列,台风,故事 · 浏览次数 : 329

小编点评

测试用例: 1 using NUnit.Framework; 2 using System; 3 using System.Collections.Generic; 4 using System.Numerics; 5 6 public class FibonacciTest 7 { 8 9 [Test] 10 public void testFib()11 {12 List tests = new List { 0, 1, 2, 3, 4, 5, -6, -96, 1000, 1001 }; 13 Random rnd = new Random(); 15 for (int i = 0; i < 10; ++i) {17 tests.Add(rnd.Next(-100, 0)); 18 } 19 tests.Add(rnd.Next(10000, 100000)); 20 tests.Add(rnd.Next(1000000, 1500000)); 21 foreach (int n in tests) {24 BigInteger found = Fibonacci.fib(n); 25 Assert.AreEqual(FibonacciRef.fib(n), found); 26 } 27 } 28 29 private static class FibonacciRef30 { 31 private static IDictionary fibs = new Dictionary(); 32 static FibonacciRef() { 35 fibs[0] = BigInteger.Zero; 36 fibs[1] = BigInteger.One; 37 fibs[2] = BigInteger.One; 38 fibs[3] = fibs[2] + fibs[1]; 39 fibs[4] = fibs[3] + fibs[2]; 40 fibs[5] = fibs[4] + fibs[3]; 41 } 42 private static BigInteger calcFib(int n) { 45 BigInteger result; 46 if (fibs.TryGetValue(n, out result)) { 47 return result; 48 } 49 if ((n & 1) == 1) { 50 int k = (n + 1) / 2; 51 BigInteger fk = BigInteger.Pow(calcFib(k), 2); 52 BigInteger fkm1 = BigInteger.Pow(calcFib(k - 1), 2); 53 result = fk + fkm1; 54 } 55 else { 56 int k = n / 2; 57 BigInteger fk = calcFib(k); 58 BigInteger fkm1 = calcFib(k - 1); 59 result = (fkm1 * fibs[3] + fk) * fk; 60 } 61 fibs[n] = result; 62 return result; 63 } 64 return result; 65 } 66 public static BigInteger fib(int n) { 67 bool neg = n < 0; 68 if (neg) { 69 n = -n; 70 } 71 if (neg && (n & 1) == 0) { 72 return -Fibonacci.fib(n); 73 } 74 return Fibonacci.fib(n); 75 } 76 return Fibonacci.fib(n); 77 } 78 } 79 } 

正文

在小岛的一个海滨小镇上,住着一个名叫苏菲的女孩。苏菲一家人靠海为生,她的生活简单而朴素,与大自然和谐共生。每天,苏菲都会来到海边,欣赏那美丽的日出和日落,感受着大海的呼吸。

然而,小岛的美丽风光并非一成不变。每年夏季,热带气旋活跃,台风频繁登陆,给小岛带来了严重的危害。

有一天,苏菲经历了一场猛烈的台风。台风带来的狂风暴雨席卷了整个小镇,树木被连根拔起,房屋倒塌,街道一片狼藉。苏菲的家也被摧毁了,她无家可归,生活陷入了困境。

在台风的影响下,苏菲失去了亲人,她感到孤独和无助。然而,她并没有放弃,她决定勇敢面对生活的挑战。

在台风过后,苏菲积极参与灾后重建工作,帮助邻居们重建家园。她用自己的双手清理废墟、种植树木,为小镇重新带来了生机。

在成长过程中,她遇到了一个气象专家,教会她一些数学知识。她决定要用自己的知识和力量去保护家园,减少自然灾害带来的损失。

她对斐波那契数列有着浓厚的兴趣,在闲暇时会用海滩上的贝壳摆出斐波那契数列的形状。

有一天,苏菲注意到一个有趣的现象:台风的路径似乎与斐波那契数列有关。她开始研究台风的形成和运动原理,发现台风的生命周期与斐波那契数列的规律有着奇妙的联系。

为了更准确地预测台风,苏菲需要处理大量的数据,进行复杂的计算。然而,她意识到传统的计算方法效率低下,无法满足实时预测的需求。于是,她开始寻找更高效的计算方法。

在一次数学课程中,苏菲学到了矩阵乘法的知识,她突然想到可以利用矩阵乘法来降低计算复杂度。她将台风的数据整理成矩阵形式,并利用矩阵乘法的快速幂算法来计算台风的运动轨迹和强度变化。

通过实践,苏菲发现利用矩阵乘法快速幂算法可以将计算复杂度降低到原来的十分之一以下,大大提高了计算效率。她将这种方法应用于台风预测模型中,取得了显著的成果。

苏菲将她的发现告诉了她的老师,得到了赞赏和支持。气象学家们将苏菲的方法应用于更广泛的天气预测中,取得了良好的效果。利用这一发现,政府可以提前做好防灾减灾的准备,减少台风带来的损失。

斐波那契数列的递推公式为:F(n) = F(n-1) + F(n-2),其中F(1) = 1,F(2) = 1。
以10为例,斐波那契数列的前10项为:
2 3 5 8 13 21 34 55

苏菲面临一个问题,当n=2000000的时候,就算用超级计算机来计算也会超时,等运算完毕,台风已经消失了,怎么处理这个问题呢?


算法实现:

 1 public static BigInteger fib(int n)
 2 {
 3     Console.WriteLine(n);  // 打印输入的参数n,用于调试
 4 
 5     BigInteger semn = 1;  // 定义一个BigInteger类型的变量semn,用于存储符号
 6     BigInteger t = 0;  // 定义BigInteger类型的变量t,用于临时存储中间计算结果
 7     BigInteger i = 1;  // 定义BigInteger类型的变量i,初始化为1
 8     BigInteger j = 0;  // 定义BigInteger类型的变量j,初始化为0
 9     BigInteger k = 0;  // 定义BigInteger类型的变量k,初始化为0
10     BigInteger h = 1;  // 定义BigInteger类型的变量h,初始化为1
11 
12     if (n < 0)  // 如果n小于0,表示需要计算负数的斐波那契数
13     {
14         n *= -1;  // 将n取绝对值
15         semn = n % 2 == 0 ? -1 : 1;  // 判断n的绝对值是否为偶数,如果是偶数,semn为-1,否则为1
16     }
17 
18     while (n > 0)  // 当n大于0时,进行循环计算斐波那契数
19     {
20         if (n % 2 != 0)  // 如果n是奇数
21         {
22             t = j * h;  // 计算j乘以h的结果,并赋值给t
23             j = i * h + j * k + t;  // 更新j的值,根据斐波那契数列的递推公式计算
24             i = i * k + t;  // 更新i的值,根据斐波那契数列的递推公式计算
25         }
26         t = h * h;  // 计算h的平方,并赋值给t
27         h = 2 * k * h + t;  // 更新h的值,根据斐波那契数列的递推公式计算
28         k = k * k + t;  // 更新k的值,根据斐波那契数列的递推公式计算
29         n = n / 2;  // 将n除以2,用于控制循环次数
30     }
31 
32     return j * semn;  // 返回计算得到的斐波那契数乘以符号semn,得到最终结果
33 }

这段代码使用了数论中的快速幂算法来计算斐波那契数,通过减少循环次数来降低计算量。让我们以n=2000000为例来解释算法的步骤。

首先,我们初始化变量i、j、h和k的值为0、1、1和0。然后,我们进入循环,当n大于0时,进行迭代计算。

在第一次迭代中,由于n=2000000是一个偶数,我们只需要更新h和k的值。我们计算h的平方并将结果存储在t中,然后更新h的值为2*k*h + t,更新k的值为k*k + t。此时,n被除以2,变为1000000。

在第二次迭代中,由于n仍然是一个偶数,我们再次只需要更新h和k的值。我们计算h的平方并将结果存储在t中,然后更新h的值为2*k*h + t,更新k的值为k*k + t。此时,n被除以2,变为500000。

依此类推,我们继续进行迭代,每次将n除以2,直到n变为1。在这个过程中,我们只需要更新h和k的值,而不需要更新i和j的值。

当n变为1时,我们进行最后一次迭代。由于n是奇数,我们需要更新i和j的值。我们计算j*h的结果并将其存储在t中,然后更新j的值为i*h + j*k + t,更新i的值为i*k + t。

最后,当n变为0时,循环终止。此时,i的值就是斐波那契数列中第2000000个数的值。

通过使用快速幂算法,我们只需要进行log(n)次循环,而不是n次循环,从而大大降低了计算量。在这个例子中,由于n=2000000,我们只需要进行log(2000000) ≈ 21次循环,而不是2000000次循环,从而提高了计算效率。


 

测试用例:

 1 using NUnit.Framework;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Numerics;
 5 
 6 public class FibonacciTest
 7 {
 8 
 9     [Test]
10     public void testFib()
11     {
12         List<int> tests = new List<int> { 0, 1, 2, 3, 4, 5, -6, -96, 1000, 1001 };
13 
14         Random rnd = new Random();
15         for (int i = 0; i < 10; ++i)
16         {
17             tests.Add(rnd.Next(-100, 0));
18         }
19         tests.Add(rnd.Next(10000, 100000));
20         tests.Add(rnd.Next(1000000, 1500000));
21 
22         foreach (int n in tests)
23         {
24             BigInteger found = Fibonacci.fib(n);
25             Assert.AreEqual(FibonacciRef.fib(n), found);
26         }
27     }
28     
29     private static class FibonacciRef
30     {
31         private static IDictionary<int, BigInteger> fibs = new Dictionary<int, BigInteger>();
32 
33         static FibonacciRef()
34         {
35             fibs[0] = BigInteger.Zero;
36             fibs[1] = BigInteger.One;
37             fibs[2] = BigInteger.One;
38             fibs[3] = fibs[2] + fibs[1];
39             fibs[4] = fibs[3] + fibs[2];
40             fibs[5] = fibs[4] + fibs[3];
41         }
42 
43         private static BigInteger calcFib(int n)
44         {
45             BigInteger result;
46             if (fibs.TryGetValue(n, out result))
47                 return result;
48 
49             if ((n & 1) == 1)
50             {
51 
52                 int k = (n + 1) / 2;
53                 BigInteger fk = BigInteger.Pow(calcFib(k), 2);
54                 BigInteger fkm1 = BigInteger.Pow(calcFib(k - 1), 2);
55                 result = fk + fkm1;
56             }
57             else
58             {
59                 int k = n / 2;
60                 BigInteger fk = calcFib(k);
61                 BigInteger fkm1 = calcFib(k - 1);
62                 result = (fkm1 * fibs[3] + fk) * fk;
63             }
64 
65             fibs[n] = result;
66             return result;
67         }
68 
69         public static BigInteger fib(int n)
70         {
71             bool neg = n < 0;
72 
73             if (neg)
74                 n = -n;
75 
76             BigInteger result = calcFib(n);
77 
78             if (neg && (n & 1) == 0)
79                 result = -result;
80 
81             return result;
82         }
83     }
84 }

 

与【算法】斐波那契数列与台风的故事相似的内容:

【算法】斐波那契数列与台风的故事

在小岛的一个海滨小镇上,住着一个名叫苏菲的女孩。苏菲一家人靠海为生,她的生活简单而朴素,与大自然和谐共生。每天,苏菲都会来到海边,欣赏那美丽的日出和日落,感受着大海的呼吸。 然而,小岛的美丽风光并非一成不变。每年夏季,热带气旋活跃,台风频繁登陆,给小岛带来了严重的危害。 有一天,苏菲经历了一场猛烈的

应届生必考的斐波那契数列 优化版本

- 开题引入斐波那契 - 代码演示: 递归、循环 - 递归 vs 循环 - 时间复杂复高,指数型O(2^n); 推导过程 - 占用线程堆栈, 可能导致栈满异常 - 压测演示 - 20230816补充尾递归 ## 斐波那契数列 打入门软件开发,斐波那契数列便是绕不过去的简单编程算法。 一个老生常谈的思

一种基于光电容积波的血压测量神经网络算法,开源、低功耗、低成本的人工智能软硬件提供者

具体的软硬件实现点击 http://mcu-ai.com/ MCU-AI技术网页_MCU-AI人工智能 心血管疾病是最严重的死亡原因之一,每年在全世界造成严重的生命损失。持续监测血压似乎是最可行的选择,但这需要一个侵入性的过程,带来了几层复杂性。这促使我们开发一种方法,通过使用光体积描记图(PPG)

使用策略模式优化你的代码

策略模式简介 策略模式(Strategy Pattern:Define a family of algorithms,encapsulate each one,and make them interchangeable.)中文解释为:定义一组算法,然后将这些算法封装起来,以便它们之间可以互换,属于一

算法金 | 我最常用的两个数据可视化软件,强烈推荐

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 预警:今天文章的描述可能会让你有点别扭;如感到不适,请及时停止 在我行走江湖的行囊中,有两件利器,tableau与matplotlib,它们足以让我应对各种数据可视化的较

算法金 | Transformer,一个神奇的算法模型!!

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 在现代自然语言处理(NLP)领域,Transformer 模型的出现带来了革命性的变化。它极大地提升了语言模型的性能和效率,而自注意力机制是其中的核心组件。 今个儿我们将

算法金 | 线性回归:不能忽视的五个问题

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 线性回归的理论依据是什么? 多重共线性是什么,它如何影响线性回归模型? 什么是自相关性,自相关性对线性回归有什么影响? 什么是异方差性,如何检测和处理异方差性? 训练数据与测试数据分布不

LLM并行训练4-megascale论文学习

算法优化 并行注意力机制 \[串行版本: y = x + MLP(LayerNorm(x + Attention(LayerNorm(x)))) \]\[并行版本: y = x + MLP(LayerNorm(x)) + Attention(LayerNorm(x)))) \]乍一看确实不是等价的,

算法金 | 必会的机器学习评估指标

构建机器学习模型的关键步骤是检查其性能,这是通过使用验证指标来完成的。 选择正确的验证指标就像选择一副水晶球:它使我们能够以清晰的视野看到模型的性能。 在本指南中,我们将探讨分类和回归的基本指标和有效评估模型的知识。 学习何时使用每个指标、优点和缺点以及如何在 Python 中实现它们 1 分类指标

算法金 | 没有思考过 Embedding,不足以谈 AI

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 在当今的人工智能(AI)领域,Embedding 是一个不可或缺的概念。如果你没有深入理解过 Embedding,那么就无法真正掌握 AI 的精髓。接下来,我们将深入探讨