POJ1001 Exponenentiation

本文介绍了一种使用C++实现的高精度计算方法,用于计算实数R的n次幂(R^n),其中R的范围是0.0到99.999,n为不超过25的正整数。文章详细解释了如何通过字符串模拟手工计算过程来处理大数值的高精度计算问题。

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

POJ1001

Problems involving the computation of exact values of very large magnitude and precision are common.
For example, the computation of the national debt is a taxing experience for many computer systems. 
This problem requires that you write a program to compute the exact value of Rn where R is a real number ( 0.0 < R < 99.999 )
and n is an integer such that 0 < n <= 25.

题意: 给定一个正实数R和正整数n,精确计算R^n。


分析: 在C\C++语言中,有符号正整数的位数最多为64位 表示范围 [-2^63, 2^63-1].实数最多也是64位(double)。对于大的数字精度可能不高。可以将正整数高精度四则运算模拟手工计算,用字符串模拟算法。

  在将一个实数转换成整数形式存储于字符串数组中设计如下几个步骤: 

  1.通过一个结构体Real 表示实数。 结构成员包括一个字符型数组 digits[]  ,和一个整型变量记录指数exp。考虑如何将字符串S构造成一个正实数。

    例如 s= "0.00670"  则digits[4] = {'0','0','0','6','7','0'};  exp = -5;

  2.将正整数数组规范化。去掉前后多余的0且同步更新指数值。 digits[2] = {'6','7'} ; exp = -4;

  3.R×R转化成 整数数相乘。

    例如 231×231 = 231×(2×10^2 + 3*10 + 1)

                = (23100+23100)+(2310+2310+2310)+(231)

    高精度乘法转换成高精度加法。字符串加法涉及到 对位,进位补零, 相加,清零(删除多余的0)。

  4.输出


C++代码实现

# include <iostream>
# include <cstring>
using namespace std;

const int MAX_DIGITS = 512;

struct Real
{
	char digits[MAX_DIGITS];
	int exp;
};

void ConstructReal(Real * real, char * str)
{
	real->exp = 0;

	if(str == NULL)
	{
		strcpy(real->digits,"0"); 
		return;
	}

	int i = 0;
	char * p = str;
	while(*p != '.')//碰到小数点
	{ //将该字符串中小数点前的数字存入数组digits
		if(*p == '\0') //该实数为整数
			break;
		real->digits[i++] = *p;
		p++;
	}

	//让指针指向小数点后的第一位数字
	if(*p != '\0')
		p++;

	while(*p != '\0')
	{
		real->digits[i++] = *p++;
		real->exp--; //更新指数
	}
	real->digits[i] = '\0';
}

void NormalizeReal(Real * real)
{
	//去掉正整数数组后面多余的0
	int i = strlen(real->digits)-1;
	while(real->digits[i]=='0' && real->exp<0)
	{
		real->digits[i] = '\0';
		real->exp++;
		i--;
	}

	//去掉前缀0
	char * p = real->digits;
	while(*p == '0')
		p++;
	strcpy(real->digits,p);

	if(real->digits[0] == '\0')
	{
		strcpy(real->digits,"0"); real->exp = 0;
	}
}

void ToSameDigits(char * str1, char * str2)
{
	int i;
	int len1 = strlen(str1), len2 = strlen(str2);
	int len = len1>len2?len1:len2;
	
	int less = len-len1;
	for(i = len1; i>=0; i--)
		str1[i+less+1] = str1[i]; //加1是为进位补零
	for(i = 0; i<=less; i++)
		str1[i] = '0';

	less = len-len2;
	for(i = len2; i>=0; i--)
		str2[i+less+1] = str2[i];
	for(i = 0; i<=less; i++)
		str2[i] = '0';
} 

char * ClearFrontZero(char * str)
{  //清零(删除多余的0)
	char * p = str;
	while(*p == '0')
		p++;
	strcpy(str,p);

	if(str[0] == '\0')
	{
		str[0] = '0'; str[1] = '\0';
	}
	return str;
}
 
char * Plus(char * str1, char * str2, char * str3=NULL)
{
	int len,i;
	if(str3 == NULL)
		str3 = str1;
	else
		strcpy(str3,str1);
	ToSameDigits(str3,str2);
	len = strlen(str3);
	for(i = len-1; i>=0; i--)
	{  //模拟手工计算,从后往前加
		str3[i] = str3[i]+str2[i]-'0';
		if(str3[i]>'9')
		{ //进位
			str3[i]-=10; str3[i-1]+=1;
		}
	}
	ClearFrontZero(str2);
	return ClearFrontZero(str3);
}	


char * Multiply(char * str1, char * str2, char * str3)
{
	int i;
	char j;
	int len1 = strlen(str1), len2 = strlen(str2);
	strcpy(str3,"0");
	for(i = len2-1; i>=0; i--)
	{  //外循环控制位置,从低位到高位
		for(j = 0;j<str2[i];j++)
		{  //内循环控制加法次数
			Plus(str3,str1); ClearFrontZero(str1);
		}
		//一次外循环进一位
		str1[len1]= '0'; str1[len1+1]='\0'; len1++;
	}
	//还原str1
	str1[len1-len2] = '\0';
	return ClearFrontZero(str3);
}	

void Multiply(Real * real1, Real * real2, Real * real3)
{
	Multiply(real1->digits, real2->digits, real3->digits);
	real3->exp = real1->exp+real2->exp;
	NormalizeReal(real3);
}

void PrintReal(Real * real, int tag)
{
	int i;
	int allLen = strlen(real->digits);
	int intLen = allLen+ real->exp;

	if(intLen>0)
	{
		for(i = 0;i<=intLen;i++)
			cout<<real->digits[i];
		if(real->exp!=0)
			cout<<'.';
		char * p = real->digits+intLen;
		cout<<p;
	}
	else
	{
		if(tag == 1)
			cout<<'0';
		cout<<'.';
		for(i = 0; i>intLen; i--)
			cout<<'0';
		cout<<real->digits;
	}
}  

int main()
{
	char s[MAX_DIGITS];
	int n; 
	Real r1, r2, r3;
	int i;

	while(cin>>s>>n)
	{
		ConstructReal(&r1,s); NormalizeReal(&r1);
		strcpy(r2.digits,r1.digits); r2.exp = r1.exp;
		strcpy(r3.digits,r1.digits); r3.exp = r1.exp;
		for(i= 1; i<n; i++)
		{
			Multiply(&r1, &r2, &r3);
			strcpy(r1.digits,r3.digits); r1.exp = r3.exp;
		}
		PrintReal(&r3,0); cout<<endl;
	}
	return 0;
}

运行结果:


    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值