计算阶层--大数乘小数问题

本文介绍了一种利用C语言实现大数阶层计算的方法。通过使用数组存储十进制数来处理超过基本数据类型限制的大整数计算问题,并提供两种优化方案:一种是逐位相乘,另一种是每四位数存储在一个int型变量中进行累乘。

C语言求100的阶层--100!

前言

思路:
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;
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shlyyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值