[ACM Steps]2.3.2 Exponentiation 大数乘法 小数的n次幂

本文介绍了一种高效计算大数(包括整数和小数)的n次幂的方法。通过自定义的数据结构来处理大数乘法,并考虑了小数点的位置调整,确保计算精度。适用于需要高精度计算的应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://acm.hdu.edu.cn/game/entry/problem/show.php?chapterid=2&sectionid=3&problemid=2


求一个大数(小数或整数)的n 次幂。


思路:

1、大数乘法

首先,将两个操作数逆转存放。

然后,将第i位和第j位相乘的结果累加存入得数的第i+j位。

再处理进位,把进位加到下一位。

最后确定得数的位数。一个A位数和一个B位数相乘的结果最长为A+B位。从得数的A+B位开始,判断是否为0,若为0 ,则得数长度减1.。

Number mul(Number A,Number B)
{
	Number C;
	int carry;
	for(int i = 0;i < A.len;i++)
		for(int j = 0;j < B.len;j++)
		{
			C.num[i + j] += (A.num[i] * B.num[j]);
		}
	int len = A.len + B.len ;
	carry = 0;
	for(int i = 0;i < len;i++)
	{
		C.num[i] += carry;
		if(C.num[i] > 9)
		{
			carry = C.num[i] / 10;
			C.num[i] = C.num[i] % 10;
		}
		else carry = 0;
	}
	
	while(C.num[len - 1] == 0)
	{
		len--;
	}
	C.len = len;
	return C;	
}



2、小数点位置

整数的n次幂必定为整数,小数的N次幂则为小数(0次幂除外),所以要确定得数小数点位置。

一个有m位小数的数的n次幂,得数有m*n位小数。


消除后置0

在处理输入数时,先判断是否存在小数点。若存在,删除小数点最后的0。

然后求出小数点后的数字位数,即小数的位数。

在完成乘法后,可能需要在小数点后补0

根据得数的长度与得数小数位数比较,

若小数位数 >= 得数长度,小数点在最前面,小数点后需要补小数点位数 - 得数长度个0.

否则,则在得数中的小数点位置插入小数点。


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

struct Number
{
	int num[200];
	int len;
	Number()
	{
		memset(num,0,sizeof(num));
		len = 0;
	}
};

Number mul(Number A,Number B)
{
	Number C;
	int carry;
	for(int i = 0;i < A.len;i++)
		for(int j = 0;j < B.len;j++)
		{
			C.num[i + j] += (A.num[i] * B.num[j]);
		}
	int len = A.len + B.len ;
	carry = 0;
	for(int i = 0;i < len;i++)
	{
		C.num[i] += carry;
		if(C.num[i] > 9)
		{
			carry = C.num[i] / 10;
			C.num[i] = C.num[i] % 10;
		}
		else carry = 0;
	}
	
	while(C.num[len - 1] == 0)
	{
		len--;
	}
	C.len = len;
	return C;	
}

int main()
{
	int n,len;
	char R[200];
	Number A;
	Number Ans;
	int decimalPoint;
	bool decimalPointFlag;
	while(scanf("%s %d",R,&n) != EOF)
	{
		len = strlen(R);
		decimalPoint = 0;
		decimalPointFlag = false;
		A.len = 0;

		for(int i = 0;i < len;i++)				//是否为小数
			if(R[i] == '.')
				decimalPointFlag = true;

		if(decimalPointFlag)
			while(R[len -1] == '0')				//去除小数点后最后多余的0
				len--;

		for(int i = len - 1; i >= 0 ; i--)
		{
			if(R[i] == '.')
				decimalPoint = len - i - 1;		//小数点后数字的位数
			else A.num[A.len++] = R[i] - '0';
		}
		
		Ans.num[0] = 1;
		Ans.len = 1;
		decimalPoint *= n;
		while(n--)
		{
			Ans = mul(Ans,A);
		}
		if(Ans.len == 0)
			printf("%c", '0');


		if(decimalPoint >= Ans.len)			//小数点位数 >= 得数长度时,要在最前面补小数点
		{
			printf("%c", '.');
			for(int i = 0;i < decimalPoint - Ans.len;i++)	//得数长度小于小数点位数时,要补0
				printf("%c", '0');
		}
		
		for(int i = Ans.len - 1;i >= 0;i--)
		{
			printf("%d", Ans.num[i]);
			if(decimalPoint != 0 && i == decimalPoint)
				printf("%c", '.');
		}
		printf("\n");

	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值