前言
思路:
1.首先应该思考的是如何在内存中保存大整数?基本数据类型无法保存的情况下,最先想到了用数组保存。
2.然后需要思考保存大数的哪种形式?Binary、Decimal、Hexadecimal?保存大数的Decimal形式比较符合习惯,也方便后面的求阶层的乘积运算。
3.然后计算存储阶层的结果的十进制数所占用的位数,用来动态申请数组内存。有编码器和译码器的知识很容想到对结果求以10为底的对数即可得到十进制所需的位数。
计算阶层:
正常的两个数相乘的思路,如720*7,7与720的从个位开始的每一位相乘,7与每一位相乘以后的结果加上上一次相乘的进位,除以10取余就是本位的值,除以10取整就是给下一次的进位。每次相乘以后的结果保存在数组中。由于是从个位开始乘起,所以数组内存中从低地址到高地址依次保存的是数据结果的低位和高位,这点有点像little endian。
100!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h> // malloc
#include <string.h> // memset
#include <math.h> // log10
#include <time.h> // clock
void Factorial(int nNumber);
int main()
{
int nNum = 0;
while (1)
{
printf("Please input the number:");
scanf("%d", &nNum);
Factorial(nNum);
}
return 0;
}
void Factorial(int nNumber)
{
int i = 0; // 计算阶层时的乘数
int j = 0; // 计算结果的每一位的索引
int nTemp = 0; // 临时乘积结果
int nCarry = 0; // 保存进位
int nLen = 0; // 保存所需的位数
int nMaxIndex = 0; // 保存最高位的索引
char* chAry = NULL; // 指向最终计算结果的指针
clock_t ckStart, ckStop;
double nBitCount = 0;
ckStart = clock(); // 开始计数
// 1.计算结果所需位数
// nNumber阶层的结果的十进制数占用的位数保存在nLen中,如5!=120,占用3位
for (i = 1; i <= nNumber; i++)
{
nBitCount = nBitCount + log10(i);
}
nLen = (int)ceil(nBitCount);
// 2.申请空间
// 每位数字存储0-9,对于每一位char型数据足够存储
chAry = (char*)malloc(nLen + 1);
memset(chAry, 0, nLen + 1);
chAry[0] = 1;
// 3.Algorithm
// 乘完以后先累加上次的进位,再计算余数和进位
for (i = 1; i <= nNumber; i++) // i为从1开始的乘积数
{
nCarry = 0;
for (j = 0; j <= nMaxIndex; j++)
{
nTemp = chAry[j] * i;
nTemp += nCarry; // 加上上次进位
chAry[j] = nTemp % 10; // 保存余数
nCarry = nTemp / 10; // 保存进位给下次循环使用
if ((nMaxIndex == j) && (nCarry !=0)) // 最高位乘积有进位
{
nMaxIndex++;
}
}
}
ckStop = clock();
// 4.逆序输出结果
printf("Factorial(%d)=", nNumber);
for ((nLen == 0) ? (i = 0) : (i = nLen - 1); i >= 0; i--)
{
printf("%d", chAry[i]);
}
printf("\r\n");
printf("Takes %f ms\r\n", ((double)(ckStop - ckStart)));
// 5.释放空间
if (chAry != NULL)
{
free(chAry);
chAry = NULL;
}
}
秒杀10000!
每4位放在一个int型数组里,作为一个整体做累乘。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h> // malloc
#include <string.h> // memset
#include <math.h> // log10
#include <time.h> // clock
void Factorial(int nNumber);
int main()
{
int nNum = 0;
while (1)
{
printf("Please input the number:");
scanf("%d", &nNum);
Factorial(nNum);
}
return 0;
}
void Factorial(int nNumber)
{
int i = 0; // 计算阶层时的乘数
int j = 0; // 计算结果的每一位的索引
int nTemp = 0; // 临时乘积结果
int nCarry = 0; // 保存进位
int nLen = 0; // 保存所需的位数
int nMaxIndex = 0; // 保存最高位的索引
int* nAry = NULL; // 指向最终计算结果的指针
clock_t ckStart, ckStop;
double nBitCount = 0;
ckStart = clock(); // 开始计数
// 1.计算结果所需位数
// nNumber阶层的结果的十进制数占用的位数保存在nLen中,如5!=120,占用3位
for (i = 1; i <= nNumber; i++)
{
nBitCount = nBitCount + log10(i);
}
nLen = (int)ceil(nBitCount)/4;
// 2.申请空间
nAry = (int*)malloc((nLen + 1)*sizeof(int));
memset(nAry, 0, (nLen + 1)*sizeof(int));
nAry[0] = 1;
// 3.Algorithm
// 乘完以后先累加上次的进位,再计算余数和进位
for (i = 1; i <= nNumber; i++) // i为从1开始的乘积数
{
nCarry = 0;
for (j = 0; j <= nMaxIndex; j++)
{
nTemp = nAry[j] * i;
nTemp += nCarry; // 加上上次进位
nAry[j] = nTemp % 10000; // 保存余数
nCarry = nTemp / 10000; // 保存进位给下次循环使用
if ((nMaxIndex == j) && (nCarry != 0)) // 最高位乘积有进位
{
nMaxIndex++;
}
}
}
ckStop = clock();
// 4.逆序输出结果
printf("Factorial(%d)=", nNumber);
printf("%d", (nLen == 0) ? 1 : nAry[nMaxIndex]);
for (i = nMaxIndex - 1; i >= 0; i--)
{
printf("%04d", nAry[i]);
}
printf("\r\n");
printf("Takes %f ms\r\n", ((double)(ckStop - ckStart)));
// 5.释放空间
if (nAry != NULL)
{
free(nAry);
nAry = NULL;
}
}
本文介绍了一种利用C语言实现大数阶层计算的方法。通过使用数组存储十进制数来处理超过基本数据类型限制的大整数计算问题,并提供两种优化方案:一种是逐位相乘,另一种是每四位数存储在一个int型变量中进行累乘。

被折叠的 条评论
为什么被折叠?



