求高精度幂
时间限制:
3000 ms | 内存限制:
65535 KB 难度:
2
- 描述
对数值很大、精度很高的数进行高精度计算是一类十分常见的问题。比如,对国债进行计算就是属于这类问题。
现在要你解决的问题是:对一个实数R( 0.0 < R < 99.999 ),要求写程序精确计算 R 的 n 次方(Rn),其中n 是整数并且 0 < =n <= 25。
- 输入
- 输入有多行,每行有两个数R和n,空格分开。R的数字位数不超过10位。
- 输出
- 对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后不要的 0 。如果输出是整数,不要输出小数点。
样例输入
95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12
样例输出
548815620517731830194541.899025343415715973535967221869852721 .00000005148554641076956121994511276767154838481760200726351203835429763013462401 43992025569.928573701266488041146654993318703707511666295476720493953024 29448126.764121021618164430206909037173276672 90429072743629540498.107596019456651774561044010001 1.126825030131969720661201
- 来源
- POJ
上传者
思路:这道题思路很简单,我的思路是先不看小数点,用大数相乘模板,记录小数位数以后加上小数点。有一点要注意的是,去除前导零的时候要注意100.00这种数,不然输出结果会是1.
代码:
#include<stdio.h>//不能连续复合运算,要保存结果 #include<stdlib.h>//所以一个技巧就是用strcpy来代替等号 #include<string.h>//c=a+b改写为strcpy(c,BigAdd(a,b)) #include<iostream> using namespace std; #define BASE 10 //确定进制 #define N 90001 //确定 最大位数+1 int l = 0; //每次记录缓存区用了多长,还原时节省时间 char res[N] = { '\0' }; //保存结果 void ini(char * x , int l); //初始化x数组 int BigCmp(char * a, char * b); // 大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1 void Clean(char * x, int l);//清除尾部的‘0’ void rev(char * x);//倒置字符串 ,与Clean联用,清除前导0 char * BigAdd(char * a, char * b);//加法 char * BigSub(char * a,char * b);//减法 char * BigMul(char * a,char * b);//乘法 char * BigPow(char * num , int n);//大数幂 char * BigMod(char * num , int mod);//大数求余 char * BigFuc(int num);//阶乘 char dot[N]={'\0'}; char s[N]={'\0'}; int main() { int k; while(scanf("%s %d",&dot,&k)!=EOF) { int flag=0; int len=strlen(dot),q=0; memset(res,'\0',sizeof(res)); for(int i=0;i<len;i++) { // if(flag==0&&dot[i]=='0') continue; if(dot[i]=='.') { flag=1; q=len-i-1; for(int j=i;j<len;j++) dot[j]=dot[j+1]; break; } } /*len=strlen(dot); for(int i=len-1;i>=0;i--) { if(dot[i]=='0')dot[i]='\0'; else break; }*/ len=strlen(dot); for(int i=0;i<len;i++) { if(dot[i]=='0') for(int j=i;j<len;j++) dot[j]=dot[j+1]; else break; } //cout<<dot<<endl; //cout<<q<<endl; q=q*k; //cout<<q<<endl; strcpy(s,BigPow(dot,k)); int m=strlen(s); if(m==q&&flag) { for(int i=m-1;i>=0;i--) if(s[i]=='0') s[i]='\0'; else break; cout<<"."; for(int i=0;i<m;i++) cout<<s[i]; cout<<endl; } else if(m<q&&flag) { for(int i=m-1;i>=0;i--) if(s[i]=='0') s[i]='\0'; else break; cout<<"."; int l=q-m; while(l--) cout<<"0"; for(int i=0;i<m;i++) cout<<s[i]; cout<<endl; } else if(m>q&&flag) { //cout<<s<<endl; int count=0; for(int i=m-1;i>=0;i--) { if(s[i]=='0') { count++; } else break; } if(q<=count) { for(int i=m-1;m-i-1<q;i--) { if(s[i]=='0') s[i]='\0'; else break; } cout<<s<<endl; } // cout<<s<<endl; else { count=0; for(int i=m-1;m-i-1<q;i--) { if(s[i]=='0') { s[i]='\0'; count++; } else break; } m=strlen(s); for(int i=0;i<m;i++) { if(m-i-1==q-count) cout<<s[i]<<"."; else cout<<s[i]; } cout<<endl; } } else cout<<s<<endl; memset(dot,'\0',sizeof(dot)); memset(s,'\0',sizeof(s)); } return 0; } int BigCmp(char * a, char * b) // 大数a < 大数b 返回1 ,相等返回0 ,a>b返回-1 { int i,j,k; int la = strlen(a),lb = strlen(b); char * temp; if(la < lb) return 1; if(la > lb) return -1; if(la == lb) { for(i = 0 ; i < la ; i++) { if(a[i] < b[i]) return 1; else if(a[i] > b[i]) return -1; } } return 0; } void ini(char * x ,int l) { int i; if(l < N) l++; for(i = 0 ; i < l ;i++) x[i] = '\0'; } void Clean(char * x,int l) { for(l--; x[l] == '0';l--) x[l] = '\0'; } void rev(char * x) { int right = strlen(x)-1; int left = 0; char temp; while(left < right) { temp = x[left]; x[left++] = x[right]; x[right--] = temp; } } char * BigAdd( char * a, char * b) { int i,j,k; int sum,la,lb,carry,flag,cmp; char *ans,*temp; ini(res,l); carry = 0; flag = 0; ans = &res[1]; if(a[0] == '-' && b[0] != '-') //判断正负 return BigSub(b,a+1); else if(a[0] != '-' && b[0] == '-') return BigSub(a,b+1); else if(a[0] == '-' && b[0] == '-') { flag = 1; a++; b++; } la=strlen(a); lb=strlen(b); if(b[0] == '0' && lb == 1) //判断0 { strcpy(ans,a); l = strlen(ans); return ans; } else if(a[0] == '0' && la ==1) { strcpy(ans,b); l = strlen(ans); return ans; } rev(a); rev(b); if(BigCmp(a,b) == 1) //保持大数a>大数b { temp = a; a = b; b =temp; k = la; la = lb; lb = k; } for(i = lb ; i < la ; i++) //空位补0 b[i] = '0'; for(i = 0 ; i < la ; i++) { sum = (a[i]-48) + (b[i]-48) + carry; if( sum < BASE ) { ans[i] = sum + 48; carry = 0; } else { ans[i] = sum - BASE + 48; carry = 1; } } if(carry) //补充最高位 { ans[i] = carry + 48; i++; } Clean(ans,i); for(i = lb ; i < la ; i++)//删除后补上的0 b[i] = '\0'; rev(ans); rev(a); rev(b); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigSub(char * a,char * b) { char *ans,*temp; int i,j,k; int borrow,flag,la,lb,sub,cmp; ini(res,l); ans = &res[1]; flag = 0; //结果没有负号 borrow = 0; if(a[0]=='-' && b[0]!='-') //被减数为负,减数为正,结果为负 { BigAdd(b,a+1); res[0] = '-'; return res; } else if(a[0]!='-' && b[0]=='-') //被减数为正,减数为负,结果为正 return BigAdd(a,b+1); else if(a[0]=='-' && b[0]=='-') //如果a,b为同时负,交换他们并都改为正,保证为“a-b”的形式 { temp=a; a=b; b=temp; a++; b++; } la = strlen(a); lb = strlen(b); if(b[0] == '0' && lb == 1) //判断0 { l = strlen(strcpy(ans,a)); return ans; } else if(a[0] == '0' && la == 1) { if(b[0] == '-') { l = strlen(strcpy(ans,b+1)); return ans; } else { res[0] = '-'; l = strlen(strcpy(ans,b)); return res; } } cmp = BigCmp(a,b); if(cmp == 0) { l = 1; res[0] = '0'; res[1] = '\0'; return res; } else if(cmp == 1) //保持大数a>=大数b { temp=a; a=b; b=temp; flag=1; //结果有负号 k = la; la = lb; lb = k; } rev(a); rev(b); for(i=0; i<lb ; i++) { sub = a[i] - borrow - b[i];//borrow借位 if( sub >= 0) { ans[i] = sub + 48; borrow = 0 ; } else // 溢出时的计算方法 { ans[i] = sub + BASE + 48; borrow = 1; } } while(i < la) // 计算剩余位 { sub = a[i] - borrow ; if(a[i] >= borrow) { ans[i] = sub ; borrow = 0; } else // 溢出时的计算方法 { ans[i] = sub +BASE ; borrow = 1; } i++; } Clean(ans,i); rev(ans); rev(a); rev(b); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigMul(char * a,char * b) { char *temp,*ans; char mul[N] = {'\0'},cal[N] = {'\0'},num[N] = {'\0'}; int i,j,k; int carry,flag,la,lb,product,lmul; int sign,sign_a,sign_b; ini(res,l); ans = &res[1]; carry = 0; flag = 0; sign = sign_a = sign_b = 0; if(a == b) //重复拷贝 b = strcpy(num,a); if(a[0] == '-' ) { flag = 1; sign_a = 1; a++; } if(b[0] == '-' ) { flag = 1; sign_b = 1; b++; } if(sign_a && sign_b) flag = 0; la = strlen(a); lb = strlen(b); if((a[0] == '0' && la == 1) || (b[0] == '0' && lb == 1)) //任何一个大数为0,结果为0 { l = 1; res[0] = '0'; res[1] = '\0'; return res; } if(BigCmp(a,b) == 1) //保证大数a >= 大数b { temp = a; a = b ; b = temp; k = la; la = lb; lb =k; } rev(a); rev(b); Clean(a,la);//清除自带的前导0 Clean(b,lb); la = strlen(a);//重新计算长度 lb = strlen(b); lmul = 0; for(i = 0 ; i < lb ; i++) { ini(mul,lmul); for( j = 0 ; j < la ; j++) { product = (a[j] - 48) * (b[i] - 48) + carry ; mul[j] = product % BASE + 48 ; carry = product / BASE ; } if(carry) { mul[j] = carry + 48; j++; carry = 0; } lmul = j; //计算缓冲区长度 if(i == 0) { strcpy(cal,mul); rev(cal); } else { //清除前导0 Clean(mul,lmul); //翻转字符串 rev(mul); //以0补位,每次相当于乘10 for(k = 0 ; k < i ;k++)//错位相加 mul[lmul++] = '0'; //保存 ans = BigAdd(cal,mul); ini(cal,strlen(cal)); strcpy(cal,ans); } } strcpy(ans,cal); rev(a); rev(b); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; } char * BigPow(char * num, int n)//快速求幂 { char * ans; char cal[N] = {'\0'},pow[N] = {'\0'}; int flag; if(n == 0) { l = 1; res[0] = '1'; res[1] = '\0'; return res; } if(strlen(num) == 1 && num[0] == '0') { l = 1; res[0] = '0'; res[1] = '\0'; return res; } ini(res,l); ans = &res[1]; flag = 0; strcpy(pow,num); //备份 cal[0] = '1'; if(pow[0] == '-' && n&1) flag = 1; while(n) { if(n&1) { ans = BigMul(cal,num); ini(cal,strlen(cal)); strcpy(cal,ans); } ans = BigMul(num,num); ini(num,strlen(num)); strcpy(num,ans); n >>= 1; } strcpy(num,pow); //还原 strcpy(ans,cal); if(flag) { res[0] = '-'; ans = res; } l = strlen(ans); return ans; }