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;
}
运行结果: