UVa 748 求幂 及相关类型转换的陷进和研究

思想:同另一篇博文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;        
 }    
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值