加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

大数阶乘

发布时间:2020-12-14 02:06:29 所属栏目:大数据 来源:网络整理
导读:以前有道作业是大数阶乘,重新捡起来实现一下,已经完全理解了该怎么做,实现细节也明白了. 一会用记事本手工写一个试试. 为了做这个题, 还总结了一个斯特林公式取对数估算n!输出结果字符串字符数量的经验公式 ^_^ /// @file src_n_factorial.cpp/// @brief 算

以前有道作业是大数阶乘,重新捡起来实现一下,已经完全理解了该怎么做,实现细节也明白了.

一会用记事本手工写一个试试.

为了做这个题, 还总结了一个斯特林公式取对数估算n!输出结果字符串字符数量的经验公式 ^_^


/// @file src_n_factorial.cpp
/// @brief 算n!的实现

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <conio.h>
#include <memory.h>
#include <time.h>

#ifndef WORD
#define WORD unsigned short
#endif

void calcFact(size_t n); ///< 算n!
size_t getFactNCharCnt(size_t n); ///< 估算n!结果字符数

int main(int argc,char* argv[]) {
    size_t n = 0;
    clock_t tmBegin = 0;
    clock_t tmEnd = 0;

    while (1) {
        printf("nplease input n to fact:");
        scanf("%u",&n);
        
        if (0 == n)
            break;
        
        printf("ncalcFact(%u) = ",n);
        tmBegin = clock();
        calcFact(n);
        tmEnd = clock();
        printf("cost time = %dSn",(tmEnd - tmBegin) / CLOCKS_PER_SEC);
    }

    /// 已经验证过了,和Windows计算器的n!(n最大3248)比对过
    /// 如果UI上显示不下,可以用 my.exe > d:txt 来运行程序
    /** run result
    
      please input n to fact:100
      
        calcFact(100) = 9332621544394415268169923885626670049071596826438162146859296389
        52175999932299156089414639761565182862536979208272237582511852109168640000000000
        00000000000000
        nResultCharCnt = 160
        cost time = 0S
        
      please input n to fact:0
          
      END,press any key to quit
    */

    printf("nEND,press any key to quitn");
    _getch();
    return 0;
}

void calcFact(size_t n) {
    size_t nArySize = getFactNCharCnt(n); ///< n!结果占用的字符数量
    size_t nIndex = 0;
    size_t nMul = 0;
    size_t nSum = 0;
    size_t nUnitMax = 10000; ///< 一个运算单位中能放的最大数.
    size_t nResultCharCnt = 0;
    WORD wCarry = 0;
    WORD* pAry = NULL;
    WORD* pTail = NULL;
    WORD* pHead = NULL;
    WORD* pCur = NULL;
    bool bFirstPrint = true;

    nArySize = (nArySize - (nArySize % sizeof(WORD))) / sizeof(WORD) + 1;
    pAry = (WORD*)malloc(nArySize * sizeof(WORD));
    if (NULL == pAry)
        return;

    memset(pAry,nArySize * sizeof(WORD));

    /// 预置了被乘数为1,新的乘数从2到n
    *(pAry + nArySize - 1) = 1;
    for (nIndex = 2,pTail = pHead = (pAry + nArySize - 1);
        nIndex <= n;
        nIndex++) {
            /// 用新的乘数从低位字节到高位字节,一直乘到有进位的最高被乘数字节.
            /// 每次的乘积都加上进位
            for (pCur = pTail; pCur >= pHead; pCur--) {
                nMul = nIndex * (*pCur) + wCarry;
                *pCur = nMul % nUnitMax;
                wCarry = (nMul - *pCur) / nUnitMax;
            }

            /// 连续累加进位到高字节
            while (wCarry > 0) {
                pHead--;
                nSum = (*pHead) + wCarry;
                (*pHead) = nSum % nUnitMax;
                wCarry = (nSum - *(pHead)) / nUnitMax;
            }
    }

    /// 找到第一个不为0的元素位置
    pHead = pAry;
    while (pHead <= pTail) {
        if (0 == *pHead)
            pHead++;
        else
            break;
    }

    while (pHead <= pTail) {
        if (bFirstPrint) {
            bFirstPrint = false;
            nResultCharCnt = pTail - pHead + 1;
            printf("%d",*pHead); ///< 不打印起始数字的开始0字符
        }
        else 
            printf("%4.4d",*pHead); ///< 打印0

        pHead++;
    }

    printf("n");

    /// n!结果字符串,一共打印出来多少字符
    printf("nResultCharCnt = %dn",nResultCharCnt * sizeof(WORD) * 2);

    free(pAry);
}

size_t getFactNCharCnt(size_t n) {
    double N = (double)n;
    const double E = 2.71828;
    return (size_t)(N * (log10(N) - log10(E)) + 4);
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读