其中__MYDEBUG__是中间计算步骤的显示开关(0或者1)
// 高精度幂计算,POJ1001, 地址: http://poj.org/problem?id=1001
// 任意长度字符串,结果输出: 小数点前后均无无意义0,如果整数部分为0,输出小数点+小数部分
// 也可以用来计算任意长度整数/小数乘法,直接调用 string stringMul(string a, string b) 即可
#include <iostream>
#include <string>
using namespace std;
// 开关,是否显示竖式乘法运算步骤
#define __MYDEBUG__ 1
// 整理字符串,如果有小数点,去除右边多余0,如果没有,去除左边多余0
// 返回小数位数*pos
string cleanUp(string s,int *pos)
{
string result = s;
size_t lpos,rpos,ppos;
ppos = s.find(".");
lpos = s.find_first_not_of("0");
rpos = s.find_last_not_of("0");
// 无小数点
if (ppos==string::npos)
{
*pos = 0;
if (lpos==string::npos) result = "0";
else result = s.substr(lpos);
}
else
{
if (rpos==ppos) // 最右非0位是小数点,无小数位
{
*pos = 0;
if (lpos==ppos) // 如果最左非0也是小数点,是0.0
{
result = "0";
}
else // 否则是01.000类
{
result = s.substr(lpos,ppos-lpos);
}
}
else // 有小数位
{
*pos = rpos-ppos;
if (lpos==ppos) // 最左非0是小数点,截取小数点后部分继续判断最左非0位,0.0100类
{
result = s.substr(ppos+1,rpos-ppos);
lpos = result.find_first_not_of("0");
result = result.substr(lpos,rpos-lpos+1);
}
else // 否则直接拼接小数点左右部分,01.0100类
{
result = s.substr(lpos,ppos-lpos)+s.substr(ppos+1,rpos-ppos);
}
}
}
return result;
}
// 字符串表示的大数相乘
string stringMul(string a, string b)
{
int lena = a.size(); // a长度
int lenb = b.size(); // b长度
int pos = 0; // 错位数
int curmul = 0, // 当前计算结果
carry = 0, // 进位
curnum = 0; // 当前位数字. 关系: 当前计算结果=进位*10+当前位数字
// 最终计算结果结果肯定小于2个字符串长度之和
// 证明:长度为lena和lenb的2个数,最大可表示为10^lena-1和10^lenb-1
// (10^lena-1)*(10^lenb-1) = 10^(lena+lenb)-10^lena-10^lenb+1 < 10^(lena+lenb),证毕.
string result = "";
result.insert(result.begin(),lena+lenb,'0');
string tempresult = "";
string current = "";
#if (__MYDEBUG__)
int wid = 40;
char fm[20];
sprintf(fm,"%%%ds\n",wid);
printf(fm,a.c_str());
sprintf(fm,"* %%%ds\n",wid-2);
printf(fm,b.c_str());
printf("-----------------------------------------\n");
#endif
for (int i=lenb-1;i>=0;i--)
{
current = ""; // 当前字符串
carry = 0; // 进位
curnum = 0; // 要添加的字符
if ((int)(b[i]-'0')==0)
{
#if (__MYDEBUG__)
sprintf(fm,"%%%ds\n",wid-pos);
printf(fm,"0");
#endif
pos++;
continue;
}
for (int j=lena-1;j>=0;j--)
{
curmul = (int)(b[i]-'0')*(int)(a[j]-'0')+carry;
carry = curmul/10;
curnum = curmul%10;
current.insert(current.begin(),1,(char)(curnum+'0'));
}
// 处理最后进位
while (carry>0)
{
current.insert(current.begin(),1,(char)(carry%10+'0'));
carry /= 10;
}
#if (__MYDEBUG__)
sprintf(fm,"%%%ds\n",wid-pos);
printf(fm,current.c_str());
#endif
// 添加给当前结果
if(result.empty())
{
result = current;
}
else // 错位相加
{
tempresult = "";
curmul = 0;
carry = 0;
curnum = 0;
for (int i=(int)current.size()-1,j=(int)result.size()-1-pos;i>=0&&j>=0;i--,j--)
{
curmul = (int)(result[j]-'0')+(int)(current[i]-'0')+carry;
carry = curmul/10;
curnum = curmul%10;
tempresult.insert(tempresult.begin(),1,(char)(curnum+'0'));
}
// 处理剩余的字符
while (carry>0)
{
tempresult.insert(tempresult.begin(),1,(char)(carry%10+'0'));
carry /= 10;
}
// 添加给结果
result.replace((int)result.size()-(int)tempresult.size()-pos,(int)tempresult.size(),tempresult);
}
// 错位+1
pos++;
}
// 清理结果
int dummy = 0;
result = cleanUp(result,&dummy);
#if (__MYDEBUG__)
printf("-----------------------------------------\n");
sprintf(fm,"%%%ds\n",wid);
printf(fm,result.c_str());
#endif
return result;
}
// 处理结果字符串,加上小数点,n是小数位数
string processResult(string s,int n)
{
// 无小数,直接返回结果
if (n==0) return s;
string result = "";
// 长度不足小数位,左边加点补0
if (s.size()<n)
{
result = ".";
result.append(n-(int)s.size(),'0');
result += s;
}
else if (s.size()==n) //刚够小数位,直接加.
{
result = "."+s;
}
else // 否则在合适位置加点
{
result = s.substr(0,s.size()-n)+"."+s.substr(s.size()-n);
}
return result;
}
int main()
{
string s;
int n;
string result;
int pos = 0;
while (cin>>s>>n)
{
pos = 0;
s = cleanUp(s,&pos);
result = s;
for (int i=1;i<n;i++) { result = stringMul(result,s); }
result = processResult(result,pos*n);
cout << result.c_str() << endl;
}
}
No comments :
Post a Comment