思想:同另一篇博文poj 1001 http://blog.csdn.net/buxizhizhou530/article/details/20407775
事实上,我是先做的的uva这个题,结果uva挂了,在poj上交,有output limit exceed 错误。(我一直搞不懂怎么会有这个错误,就算有错,又没有死循环,怎么会输出都溢出了呢?)poj上这题数据强一些,这个代码有点问题,但在uva上过了(交了poj之后,uva恢复后,才发现uva挂之前交的代码过了。。。)。poj那题主要是修改了去除后缀0函数,去除有限个后缀0。经本人一个一个cout,终于发现为什么会OLE了,主要是int 与 unsigned int 运算,int 转换成unsigned int,而这个int值恰好是负的,负值赋给unsigned,是其对该类型的取值个数求模后的值。如-1赋给8位的unsigned int ,则结果是255。
这里,在输出时,即return 0上面第一个else语句里,输出的n*d-nl-s.size()是4294967294(比32位的unsigned int 最大值少1,即2的32次方-2),而n*d-nl是-1,s.size()是1,所以前者转换成unsigned int 是2的32次方减1,再减1,即输出为那个数。。
总结:string.size()返回的是string::size_type类型,该类型被定义为与unsigned型具有相同含义。C++ Primer中建议不要把size的返回值赋给int变量。(几个原因见P73)
这里是将其与int型变量进行运算了。这牵涉到int型与unsigned型运算的问题,int型会转换成unsigned型;(CP p155)
而int型如果是负数,转换成unsigned型就会有副作用,是负数对2的某次方取模后的值。(CP p32)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#define MAXN 200
using namespace std;
struct bign
{
int len,s[MAXN];
bign(){ memset(s,0,sizeof(s)); len=1;}
bign operator=(const char* num)
{
len=strlen(num);
for(int i=0;i<len;++i) s[i]=num[len-1-i]-'0';
return *this;
}
bign operator*(const bign& b) const
{
bign c;
c.len=len+b.len;
for(int i=0;i<len;++i)
for(int j=0;j<b.len;++j)
c.s[i+j]+=s[i]*b.s[j];
for(int i=0;i<c.len-1;++i)
{
c.s[i+1]+=c.s[i]/10;
c.s[i]%=10;
}
c.clean();
return c;//额,这里竟然忘了~
}
void clean()
{
while(!s[len-1]&&len>1)
len--;
}
string str() const
{
string res="";
for(int i=0;i<len;++i) res=(char)(s[i]+'0')+res;
return res;
}
};
void zs_zero(bign &b);
int xs_zero(bign &b);
void exponent(bign &b,int n,bign &c);
istream& operator>>(istream &in, bign &x)
{
string s;
cin>>s;
x=s.c_str();
return in;
}
ostream& operator<<(ostream &out, const bign &x)
{
out<<x.str();
return out;
}
int main()
{
char temps[10];
int n;
while((scanf("%s%d",temps,&n))==2)
{
int d=0;//小数位数
int len=strlen(temps);
for(int i=0,j=0;i<len;++i)
{
if(temps[i]=='.') d=len-1-i;
else
{
temps[j++]=temps[i];
}
}//for
temps[len-1]='\0';//去掉小数点后长度恰少1
//cout<<"d:"<<d<<endl;
//计算
bign num;
num=temps;
bign res;
exponent(num,n,res);
zs_zero(res);
int nl=xs_zero(res);//nl为删去的后导0个数
//输出
string s=res.str(); //cout<<"nl:"<<nl<<endl<<"s:"<<s<<endl;
string::size_type ix=0;
for(;ix!=s.size();++ix)
if(s[ix]!='0') break;
if(ix==s.size()) {cout<<"."<<endl; continue;}//输入为0,直接输出.
if(n*d-nl<=s.size())//小数位数比去0后的数值位数少
{
for(ix=0;ix!=s.size()-(n*d-nl);++ix)
cout<<s[ix];
cout<<".";
for(;ix!=s.size();++ix)
cout<<s[ix];
cout<<endl;
}
else
{
cout<<"."; /*cout<<n*d-nl-s.size()<<endl<<n*d<<endl<<nl<<endl<<s.size()<<endl;
cout<<n*d-nl<<endl<<n*d-nl-s.size()<<endl;system("pause");*/
for(int i=0;i<n*d-nl-s.size();++i)
cout<<"0";
cout<<s<<endl;
}
}//while
return 0;
}
void zs_zero(bign &b)
{//去除整数部分的前导0,与clean()的不同在于,长度可以为0
while(!b.s[b.len-1]&&b.len>0) b.len--;
}
int xs_zero(bign &b)
{//去除小数部分的后导0
int i=0;//指示后导0的个数
string str=b.str();
//cout<<"str:"<<str<<endl;
string::size_type ix=str.size()-1;
for(;ix>=0;--ix)//注意这里判断条件ix可以为0
{//ix初始值注意减1啊,C风格字符串可以访问strlen位置,为空字符,而string的size位置非法
if(str[ix]!='0') {i=str.size()-1-ix; break;}//判断的是字符'0'
//cout<<str[ix]<<" "<<ix<<endl;
}//i=str.size()-1-ix;
//cout<<"size:"<<str.size()<<"ix:"<<ix<<"i:"<<i<<endl;
//cout<<str.size()-1-ix<<endl;
//cout<<str.size()<<endl;
str.erase(str.size()-i,i);//删除最后i个字符
b=str.c_str();
return i;
}
void exponent(bign &b,int n,bign &c)
{//计算b的n次幂,保存在c;会修改b的值
c="1";
while(n>0)
{//cout<<"n:"<<n<<"b:"<<b<<endl;
if(n%2==1) c=c*b; //{cout<<"c:"<<c<<endl;}
b=b*b; //cout<<"b:"<<b<<endl;
n=n/2;
}
}