求高精度幂
Time Limit: 500MS | Memory Limit: 10000K | |
Total Submissions: 170398 | Accepted: 41283 |
Description
对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。
现在要你解决的问题是:对一个实数R( 0.0 < R < 99.999 ),要求写程序精确计算 R 的 n 次方(R n),其中n 是整数并且 0 < n <= 25。
现在要你解决的问题是:对一个实数R( 0.0 < R < 99.999 ),要求写程序精确计算 R 的 n 次方(R n),其中n 是整数并且 0 < n <= 25。
Input
T输入包括多组 R 和 n。 R 的值占第 1 到第 6 列,n 的值占第 8 和第 9 列。
Output
对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后不要的 0 。如果输出是整数,不要输出小数点。
Sample Input
95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12
Sample Output
548815620517731830194541.899025343415715973535967221869852721 .00000005148554641076956121994511276767154838481760200726351203835429763013462401 43992025569.928573701266488041146654993318703707511666295476720493953024 29448126.764121021618164430206909037173276672 90429072743629540498.107596019456651774561044010001 1.126825030131969720661201
题目分析:
由于该题数字太大,用pow函数是无法解决的,所以我们需要用字符数组来解决问题,采用STL创建一个string类型的可变数组可以方便我们进行操作。所需的步骤有六步:
①输入处理:由于我们正常输入,最高位是存在数组的最低位,所以我们需要先对其进行处理,将其倒置,并去掉小数点,并记录小数点的位置。
②模拟手算的过程:用mul表示每一次被乘的数(记得每乘完一个数都要将结果放入mul用于下一次运算),将乘数用一个数组ori记录(就等于输入的数据,因为它是不会变的),再用一个tmp数组存储每一位数操作得出的结果,用res数组存储总的结果(res是每一次tmp结果相加)具体过程看代码标注。
③插入小数点:用一个迭代器找到所需插入的位置,用insert函数即可,然后将mul数组(我最后懒得再将res=mul)翻转便于后面输出
④去除多余的0:用left和right分别代表小数点的左边和右边,找到有效数字的位置,最后根据left和right的位置进行输出。(要考虑是否有小数)
⑤最后就是简单的循环输出咯 代码中还有更详细的解释。
测试数据网上可以搜到,可以去看看自己哪一步错了。
话不多说(好像挺啰嗦的),看代码
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
int main()
{
string inp;//接收数据;
string mul;//处理后的数据
string res;//最终数据
int n;//阶乘
while(cin>>inp>>n)
{
res="0";
int len_inp=int(inp.length());
int pos=0;//小数点位置
for(int i=len_inp-1;i>=0;i--)//寻找小数点并且将数据存入新的s
{
if(inp[i]!='.')
mul+=inp[i];
else
pos=len_inp-i-1;
}
string tmp;//每乘一个数的结果
int mul_cnt;//乘数
int len_mul = len_inp-1;
int i,j;
int res_len = len_mul;
res=mul;
pos=pos*n;//小数点最终位置
string ori=mul;//每次乘的数
while(n--)
{
mul.clear();
mul=res;//重新定义被乘数
len_mul=res_len;//重新规定被乘数的长度
for(i=0;i<len_inp-1;i++)//第一重,原始数据的每一个数
{
mul_cnt=ori[i]-'0';
int jinwei=0;
for(j=0;j<len_mul;j++)//第二重,乘数乘以被乘数的每一个数字
{
int fir_cnt=0;
fir_cnt=(mul_cnt*(mul[j]-'0')+jinwei)%10;//当前个位数结果
jinwei=(mul_cnt*(mul[j]-'0')+jinwei)/10;//十位数结果
tmp+=fir_cnt+'0';//存入tmp中
}
if(jinwei)//如果被乘数的最后一位乘完还有进位,则需在tmp后多加一位
tmp+=jinwei+'0';
if(i==0)//因为乘法中第一次乘不用与原来的相加。手算的第一步
{
res.clear();//有点多余,保险
res=tmp;//直接等于就好
}
else
{
if(res.length()<(tmp.length()+i))//因为相加需要移位,为了方便,将他们的位数都用0补齐
{
int cha=int(tmp.length()-res.length())+i;//i是所需移位的距离
while(cha--)
{
res+='0';
}
}
int jinwei=0;
int x;
for(x=0;x<tmp.length();x++)
{
int sum=(res[x+i]-'0'+tmp[x]-'0')+jinwei;//将他们的字符提出来int化
jinwei=0;
if(sum>=10)
{
sum%=10;
jinwei=1;
}
res[x+i]=sum+'0';
}
if(jinwei)//与前面一样
res+='1';
}
res_len=int(res.length());//千万要记得重新测量长度,否则下次就不知道要乘几位数了
tmp.clear();//将这次的结果清零
}
}
//清零与输出操作
string::iterator it;
it=mul.begin();
mul.insert(it+pos,'.');//找到位置插入
reverse(mul.begin(), mul.end());
int co_pos=int(mul.find('.'));//找出小数点的位置
int left,right;
//分别从最左边与最右边开始,遇到非零就停下
for(left=0;left<co_pos;left++)
{
if(mul[left]!='0')
break;
}
for(right=int(mul.length())-1;right>co_pos;right--)
{
if(mul[right]!='0')
break;
}
if(right==co_pos)//特别注意当没有小数的时候
{
for(int i=left;i<right;i++)
cout<<mul[i];
}
else
{
for(int i=left;i<=right;i++)
cout<<mul[i];
}
cout<<endl;
mul.clear();//记得清零,这一组数据结束
}
return 0;
}