斐波那契数列大数加法

昨天做完n!的大数实现,再看变形的大数加法(fibonacci)实现,感觉好多了.

空间估算经验公式

size_t fnCalcFibonacciArySize(size_t n) {
    /// 从资料上看到的经验公式
    return (size_t)(n / 4 + 4);
}

实现

/// @file \exam_fibonacci\main.cpp
/// @brief 斐波那契数列大数加法
///     ary[0] = 1, ary[1] = 1; ary[2] = ary[0] + ary[1], ary[n] = ary[n-1] + ary[n-2]
///     大数数组的估算 ary[n/4 + 4]

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>

#ifndef WORD
#define WORD unsigned short
#endif

void fnCalcFibonacci(); ///< 计算斐波那契数列n的大数
size_t fnCalcFibonacciArySize(size_t n); ///< 估算斐波那契数列n时的大数数组size
void fnCalcFibonacci(WORD* pAryAdd1, WORD* pAryAdd2, WORD* pArySum, size_t nArySize);
void fnPrintFibonacci(WORD* pArySum, size_t nArySize);

int main(int argc, char* argv[]) {
    do 
    {
        fnCalcFibonacci();
        printf("press 'c' to continue, other key to quit\n");
        if ('c' != _getch())
            break;
    } while (1);

    /// 和其它人实现的fibonacci大数加法结果比对过, 正确^_^
    /** run result
    please input fibonacci's n:0
    
    press 'c' to continue, other key to quit
    please input fibonacci's n:1
  
    press 'c' to continue, other key to quit
    please input fibonacci's n:2
    2
    press 'c' to continue, other key to quit
    please input fibonacci's n:100
    573147844013817084101
    press 'c' to continue, other key to quit
    please input fibonacci's n:200
    453973694165307953197296969697410619233826
    press 'c' to continue, other key to quit
    please input fibonacci's n:1000
    70330367711422815821835254877183549770181269836358732742604905087154537118196933
    57974224949456261173348775044924176599108818636326545022364710601205337412127386
    7339111198139373125598767690091902245245323403501
    press 'c' to continue, other key to quit
    */

    return 0;
}

void fnCalcFibonacci() {
    size_t n = 0;
    size_t nArySize = 0;
    size_t nIndex = 0;
    WORD* pAry1 = NULL;
    WORD* pAry2 = NULL;
    WORD* pAry3 = NULL;

    WORD* pAryAdd1 = NULL;
    WORD* pAryAdd2 = NULL;
    WORD* pArySum = NULL;
    WORD* pAryTmp = NULL;

    printf("please input fibonacci's n:");
    fflush(stdin); ///< 清空输入缓冲区
    scanf("%u", &n);
    nArySize = fnCalcFibonacciArySize(n);

    /// 算出需要开配的WORD数组大小
    nArySize = (nArySize - (nArySize % sizeof(WORD))) / sizeof(WORD) + 1;

    /// 开辟资源
    pAry1 = (WORD*)malloc(nArySize * sizeof(WORD));
    if (NULL != pAry1) {
        memset(pAry1, 0, nArySize * sizeof(WORD));
        pAry1[nArySize - 1] = 1;
    }

    pAry2 = (WORD*)malloc(nArySize * sizeof(WORD));
    if (NULL != pAry2) {
        memset(pAry2, 0, nArySize * sizeof(WORD));
        pAry2[nArySize - 1] = 1;
    }

    pAry3 = (WORD*)malloc(nArySize * sizeof(WORD));
    if (NULL != pAry3) {
        memset(pAry3, 0, nArySize * sizeof(WORD));
    }
    
    /// 计算Fibonacci大数数列
    if ((NULL != pAry1) && (NULL != pAry2) && (NULL != pAry3)) {
        pAryAdd1 = pAry1;
        pAryAdd2 = pAry2;
        pArySum = pAry3;

        for (nIndex = 2; nIndex <= n; nIndex++) {
            fnCalcFibonacci(pAryAdd1, pAryAdd2, pArySum, nArySize);

            /// 如果不是最后一次加法, 重新设置数组(被加数,加数,和)
            if (nIndex != n) {
                pAryTmp = pAryAdd1;
                pAryAdd1 = pAryAdd2;
                pAryAdd2 = pArySum;
                pArySum = pAryTmp;
            }
        }

        /// 打印结果
        fnPrintFibonacci(pArySum, nArySize);
    }

    /// 释放资源
    if (NULL != pAry1) {
        free(pAry1);
        pAry1 = NULL;
    }

    if (NULL != pAry2) {
        free(pAry2);
        pAry2 = NULL;
    }

    if (NULL != pAry3) {
        free(pAry3);
        pAry3 = NULL;
    }
}

void fnCalcFibonacci(WORD* pAryAdd1, WORD* pAryAdd2, WORD* pArySum, size_t nArySize) {
    size_t nIndex = 0;
    size_t nPos = nArySize - 1;
    int iSum = 0;
    int iCarry = 0;

    memset(pArySum, 0, sizeof(WORD) * nArySize); ///< ! sizeof(WORD)

    /// 为了防止数组nPos越界操作, 循环的次数必须比数组size小2
    for (nIndex = 0; nIndex < (nArySize - 1); nIndex++, nPos--) {
        iSum = pAryAdd1[nPos] + pAryAdd2[nPos] + iCarry;
        pArySum[nPos] = iSum % 10000;
        iCarry = (iSum - iSum % 10000) / 10000;
    }
}

void fnPrintFibonacci(WORD* pArySum, size_t nArySize) {
    bool bFirstShow = true;
    size_t nIndex = 0;

    for (nIndex = 0; nIndex < nArySize; nIndex++) {
        if (bFirstShow) {
            /// 找到第一个不为零的数据
            if (0 == pArySum[nIndex])
                continue;

            bFirstShow = false;
            printf("%d", pArySum[nIndex]);
        }
        else {
            printf("%4.4d", pArySum[nIndex]);
        }
    }

    printf("\n");
}

size_t fnCalcFibonacciArySize(size_t n) {
    /// 从资料上看到的经验公式
    return (size_t)(n / 4 + 4);
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值