斐波那契数列的高精度算法

斐波那契数列:1,1,2,3,5,8.......某一项为前两项的和的数列称为斐波那契数列

故有递推公式:f(n) = f(n-1) + f(n-2)。边界条件:n=1时和n=2。f(1) = 1 ,f(2)=1

所以求第N项斐波那契数列的递归代码为:

int f(int n)
{
    if (n == 1)
    {
        return 1;
    }
    if (n == 2)
    {
        return 1;
    }
    return f(n - 1) + f(n - 2);
}

斐波那契的非递归算法思想:将数列的第n项看成一个累加和,当n=1和n=2时候返回1,从n=3开始,用num1和num2代表第n-1和n-2项,使用temp记录加和,使用sum来表示第n项的值,每次循环后将temp的值累加到sum上,将n-2置为n-1的值,将num1置为sum的值。代码如下:

int fun(int n)
{
    int sum = 0;
    int num1 = 1;
    int num2 = 1;
    if (n == 1 || n == 2)
    {
        return 1;
    }
    for (int i = 3; i <= n; ++i)
    {
        sum = num1 + num2;
        num1 = num2;
        num2 = sum;
    }
    return sum;
}

如果当n超过一个数值后,则会造成存储溢出,这是因为int的最大存储值为2的31次方-1。此时需要使用高精度算法来进行斐波那契数列的计算。在此之前先看一个高精度加法的例子

#define MAX_SIZE 500
int max(int a, int b)
{
    return a > b ? a : b;
}
int min(int a, int b)
{
    return a < b ? a : b;
}
void add()
{
    char s1[MAX_SIZE], s2[MAX_SIZE];
    int num1[MAX_SIZE] = {0}, num2[MAX_SIZE] = {0}, sum[MAX_SIZE] = {0};
    cin >> s1;
    cin >> s2;
    int num1_len = strlen(s1);
    int num2_len = strlen(s2);
    for (int i = 0; i < num1_len; i++)
    {
        num1[num1_len - i - 1] = s1[i] - '0'; //转成数字后倒排
    }
    for (int i = 0; i < num2_len; i++)
    {
        num2[num2_len - i - 1] = s2[i] - '0';
    }
    //加法操作
    int add_len = max(num1_len, num2_len) + 1;
    for (int i = 0; i < add_len; ++i)
    {
        sum[i] += num1[i] + num2[i];
        sum[i + 1] = sum[i] / 10;
        sum[i] = sum[i] % 10;
    }
    if (sum[add_len - 1] == 0)
    {
        add_len--;
    }
    for (int i = add_len-1; i >=0; --i)
    {
        cout << sum[i];
    }
}

算法的思想是:使用char类型数组来接受输入的大数,将char类型的大数数组转为Int类型的数组来表示一个大数,注意这里需要将顺序转置,方便加法计算(方便从低位开始进行计算,小的数字高位没有则补零)。加法的计算规则也很简单:两数之和除以10用余数代表当前的位的数,商代表进位数。

接下来给出斐波那契数列的高精度算法。

首先是使用一个类来定义一个高精度的整数。定义如下:

using namespace std;
class NumberH
{
public:
    //构造函数
    NumberH(const char* s = 0);
    NumberH(char s);
    //拷贝构造
    NumberH(const NumberH& num);
    ~NumberH();
public:
    //重载+
    NumberH operator +(const NumberH& num) const;
    //拷贝赋值(注意这里返回是this对象的引用)
    NumberH& operator =(const NumberH& num);
    char* get_str()
    {
        return m_str;
    }
private:
    char* m_str = 0;
};
std::ostream& operator <<(std::ostream& os,  NumberH& num);

.cpp文件如下:

#include "numberh.h"
using namespace std;
int max(int a, int b)
{
    return a > b ? a : b;
}
void reverse_char_array(char* str)
{
    if(str) {
        int len = strlen(str);
        for(int i = 0; i <= (len / 2); ++i) {
            int j = len - i - 1;
            char temp = *(str + i);
            *(str + i) = *(str + j);
            *(str + j) = temp;
        }
    }
}
char* reverse_array(char* str)
{
    char* ret = 0;
    if(str) {
        int len = strlen(str);
        ret = new char[len + 1];
        for(int i = 0; i < len; ++i) {
            int j = len - i - 1;
            *(ret + j) = *(str + i);
        }
        *(ret + len) = '\0';
    }
    delete[] str;
    return ret;
}

NumberH::NumberH(const char* s)
{
    if(s) {
        int len = strlen(s);
        m_str = new char[len + 1];
        strcpy(m_str, s);
    } else {
        m_str = new char[1];
        m_str = '\0';
    }
}

NumberH::NumberH(char s)
{
    m_str = new char[2];
    *(m_str) = s;
    *(m_str + 1) = '\0';
}

NumberH::NumberH(const NumberH& num)
{
    m_str = new char[strlen(num.m_str) + 1];
    strcpy(m_str, num.m_str);
}

NumberH::~NumberH()
{
    if(!m_str) {
        delete[] m_str;
    }
}
/**
 * @brief NumberH::operator + 实现两个高精度整数的加法操作
 * @param num 高精度整数
 *        思想是将char->指向的字符数组,从最后端每一位转为int进行加法操作。
 *        对结果再转为char,构造一个新的高精度整数
 *
 * @return 返回一个高精度整数
 */
NumberH NumberH::operator+(const NumberH& num) const
{
    if(num.m_str) {
        int num_len = strlen(num.m_str);
        int this_len = strlen(m_str);
        int add_len = max(num_len, this_len) + 1;
        char* ret = new char[add_len + 1];
        memset(ret, '0', add_len);
        int* num_array = new int[add_len]();
        int* this_array = new int[add_len]();
        //char--->int : char - '0'
        for(int i = num_len - 1; i >= 0; --i) {
            int j = num_len - i - 1;
            *(num_array + j) = (*(num.m_str + i)) - '0';
        }
        for(int i = this_len - 1; i >= 0; --i) {
            int j = this_len - i - 1;
            *(this_array + j) = (*(m_str + i)) - '0';
        }
        //int--->char: int + '0'
        for(int i = 0; i < add_len - 1; ++i) {
            int sum = *(num_array + i) + *(this_array + i);
            int temp = *(ret + i) - '0';
            sum += temp;
            *(ret + i + 1) = sum / 10 + '0';
            *(ret + i) = sum % 10 + '0';
        }
        delete[] num_array;
        delete[] this_array;
        //添加\0结束符
        if(*(ret + add_len - 1) == '0') {
            *(ret + add_len - 1) = '\0';
        } else {
            *(ret + add_len) = '\0';
        }
        ret = reverse_array(ret);
        return NumberH(ret);
    }
    return NumberH();
}

NumberH& NumberH::operator =(const NumberH& num)
{
    //自我赋值检测
    if(this == &num) {
        return *this;
    }
    delete[] m_str;
    m_str = new char[strlen(num.m_str) + 1];
    strcpy(m_str, num.m_str);
    return *this;
}
ostream& operator <<(ostream& os, NumberH& num)
{
    return os << num.get_str();
}

上述代码基本是基于高精度整数加法的,有些许不一样:

NumberH类使用的是一个char*类型的指针指向一块内存空间的,使用new char[len]进行动态分配。并不像上面加法中使用固定长度的char数组。

因此,需要注意的是:在重载+函数中返回的NumberH分配的空间是max(len1,len2)+2,并不是+1,这是因为需要在最后位上加上'\0'的结束符。否则使用strlen()函数会出现错误导致程序报错。

另外进位的计数是求得当前位与'0'字符得差值(通过ASCII表的方法)求得。也就是int---->char需要进行加法(+'0'),char---->int需要进行减法(-'0')。

最后给出高精度算法的斐波那契数列第N项求解代码:

using namespace std;

NumberH Fibonacci(int n)
{
    if(n == 1 || n == 2) {
        NumberH num('1');
        return num;
    }
    NumberH num1('1');
    NumberH num2('1');
    NumberH ret('0');
    for(int i = 3; i <= n; ++i) {
        ret = num1 + num2;
        num1 = num2;
        num2 = ret;
    }
    cout << ret << endl;
    return ret;
}

int main(int argc, char* argv[])
{
    Fibonacci(25);
    return 0;
}

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
知识总结 1 一、整除的性质: 3 二、数的整除特征 3 三、奇偶的性质 4 四、模p运算 4 五、同余的性质 4 六、余数检验 5 七、素数 6 八、素数的检验 7 九、最大公约数 8 十、算术基本定理 9 十一、一些数论的定理 9 十二、二次剩余 9 十三、梅森数 10 十四、完全数 11 十五、费马数 12 十六、完全平方数 12 十七、水仙花数 13 十八、西西弗斯数 13 十九、高度合成数 13 二十、斐波那契数 13 二十一、亲和数 14 二十二、欧拉数 14 二十三、欧拉的其他公式 15 二十四、欧拉方程 15 二十五、勾股数的特点 16 二十六、勾股数系的系和组 17 二十七、勾股数系的性质 17 二十八、二元一次不定方程 18 二十九、中国同余式 18 三十、数列 18 三十一、常识 19 三十二、幻方 19 三十三、克拉茨命题 20 三十三、用牛顿叠代法求高精度倒数 21 三十四、用二分法求解n! 21 三十五、高精度求乘幂 21 三十六、高精度求实数乘幂 22 三十七、高精度求对数 23 三十八、乘法的快速傅立叶转换 23 三十九、FFT 乘法 24 四十、高精度求开方 25 四十一、对原函数进行高精度求解 26 四十二、巴什博奕(Bash Game): 27 四十三、威佐夫博奕(Wythoff Game): 27 四十四、尼姆博奕(Nimm Game): 28 四十五、取火柴游戏 29 四十六、取硬币游戏 30 四十七、分金币 30 四十八、三人行游戏 31 四十九、3个教士和3个土人 31 五十、分酒问题 32 五十一、砝码 33 五十二、杨辉三角 34 五十三、图论的一些定理: 37 五十四、二部图 38 五十五、排列组合问题 39 五十六、计数问题 39 五十七、微积分公式 41 五十八、三角函数公式 43 五十九、空间解析几何和向量代数: 44 六十、多元微积分 44 六十一、多元函数微分法及应用 47 六十二、微分法在几何上的应用: 48 六十三、级数: 49 六十四、微分方程: 52 六十五、数学常用公式 53 六十六、二维图形的周长与面积公式 56 六十七、程序 58
斐波那契数列是一个数列,其中每个数字都是前两个数字的和。通常,斐波那契数列的前两个数字是0和1。 如果要计算斐波那契数列中的第n个数字(n从0开始),可以使用高精度算法来处理,以避免溢出或精度丢失。以下是一个使用高精度算法计算斐波那契数列的示例代码: ```cpp #include <iostream> #include <vector> // 高精度加法 std::vector<int> add(const std::vector<int>& num1, const std::vector<int>& num2) { std::vector<int> result; int carry = 0; int i = num1.size() - 1; int j = num2.size() - 1; while (i >= 0 || j >= 0 || carry > 0) { int sum = carry; if (i >= 0) { sum += num1[i]; i--; } if (j >= 0) { sum += num2[j]; j--; } result.insert(result.begin(), sum % 10); carry = sum / 10; } return result; } // 计算斐波那契数列的第n个数字(高精度) std::vector<int> fibonacci(int n) { std::vector<int> fibPrev{0}; std::vector<int> fibCurr{1}; for (int i = 2; i <= n; i++) { std::vector<int> fibNext = add(fibPrev, fibCurr); fibPrev = fibCurr; fibCurr = fibNext; } return fibCurr; } int main() { int n = 100; // 计算斐波那契数列的第100个数字 std::vector<int> result = fibonacci(n); std::cout << "Fibonacci number at position " << n << ": "; for (int digit : result) { std::cout << digit; } std::cout << std::endl; return 0; } ``` 在上述示例中,我们定义了一个 `add` 函数来实现高精度的加法。然后,我们使用 `fibonacci` 函数来计算斐波那契数列的第n个数字。通过使用高精度的加法来计算每个数字,我们可以避免溢出或精度丢失。 请注意,随着n的增加,计算斐波那契数列高精度解决方案会变得更加耗时和占用内存。因此,在实际应用中,需要根据具体需求权衡使用高精度算法的必要性和性能要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值