高精度运算
首先一个别人总结的模版,我觉得很好就引用一下
/**高精度模版*/ #include <stdio.h> #include <string.h> #include <iostream> using namespace std; const int MAXL = 500; struct BigNum { int num[MAXL]; int len; }; //高精度比较 a > b return 1, a == b return 0; a < b return -1; int Comp(BigNum &a, BigNum &b) { int i; if(a.len != b.len) return (a.len > b.len) ? 1 : -1; for(i = a.len-1; i >= 0; i--) if(a.num[i] != b.num[i]) return (a.num[i] > b.num[i]) ? 1 : -1; return 0; } //高精度加法 BigNum Add(BigNum &a, BigNum &b) { BigNum c; int i, len; len = (a.len > b.len) ? a.len : b.len; memset(c.num, 0, sizeof(c.num)); for(i = 0; i < len; i++) { c.num[i] += (a.num[i]+b.num[i]); if(c.num[i] >= 10) { c.num[i+1]++; c.num[i] -= 10; } } if(c.num[len]) len++; c.len = len; return c; } //高精度减法,保证a >= b BigNum Sub(BigNum &a, BigNum &b) { BigNum c; int i, len; len = (a.len > b.len) ? a.len : b.len; memset(c.num, 0, sizeof(c.num)); for(i = 0; i < len; i++) { c.num[i] += (a.num[i]-b.num[i]); if(c.num[i] < 0) { c.num[i] += 10; c.num[i+1]--; } } while(c.num[len] == 0 && len > 1) len--; c.len = len; return c; } //高精度乘以低精度,当b很大时可能会发生溢出int范围,具体情况具体分析 //如果b很大可以考虑把b看成高精度 BigNum Mul1(BigNum &a, int &b) { BigNum c; int i, len; len = a.len; memset(c.num, 0, sizeof(c.num)); //乘以0,直接返回0 if(b == 0) { c.len = 1; return c; } for(i = 0; i < len; i++) { c.num[i] += (a.num[i]*b); if(c.num[i] >= 10) { c.num[i+1] = c.num[i]/10; c.num[i] %= 10; } } while(c.num[len] > 0) { c.num[len+1] = c.num[len]/10; c.num[len++] %= 10; } c.len = len; return c; } //高精度乘以高精度,注意要及时进位,否则肯能会引起溢出,但这样会增加算法的复杂度, //如果确定不会发生溢出, 可以将里面的while改成if BigNum Mul2(BigNum &a, BigNum &b) { int i, j, len = 0; BigNum c; memset(c.num, 0, sizeof(c.num)); for(i = 0; i < a.len; i++) { for(j = 0; j < b.len; j++) { c.num[i+j] += (a.num[i]*b.num[j]); if(c.num[i+j] >= 10) { c.num[i+j+1] += c.num[i+j]/10; c.num[i+j] %= 10; } } } len = a.len+b.len-1; while(c.num[len-1] == 0 && len > 1) len--; if(c.num[len]) len++; c.len = len; return c; } //高精度除以低精度,除的结果为c, 余数为f void Div1(BigNum &a, int &b, BigNum &c, int &f) { int i, len = a.len; memset(c.num, 0, sizeof(c.num)); f = 0; for(i = a.len-1; i >= 0; i--) { f = f*10+a.num[i]; c.num[i] = f/b; f %= b; } while(len > 1 && c.num[len-1] == 0) len--; c.len = len; } //高精度*10 void Mul10(BigNum &a) { int i, len = a.len; for(i = len; i >= 1; i--) a.num[i] = a.num[i-1]; a.num[i] = 0; len++; //if a == 0 while(len > 1 && a.num[len-1] == 0) len--; } //高精度除以高精度,除的结果为c,余数为f void Div2(BigNum &a, BigNum &b, BigNum &c, BigNum &f) { int i, len = a.len; memset(c.num, 0, sizeof(c.num)); memset(f.num, 0, sizeof(f.num)); f.len = 1; for(i = len-1;i >= 0;i--) { Mul10(f); //余数每次乘10 f.num[0] = a.num[i]; //然后余数加上下一位 ///利用减法替换除法 while(Comp(f, b) >= 0) { f = Sub(f, b); c.num[i]++; } } while(len > 1 && c.num[len-1] == 0) len--; c.len = len; } void print(BigNum &a) //输出大数 { int i; for(i = a.len-1; i >= 0; i--) printf("%d", a.num[i]); puts(""); } //将字符串转为大数存在BigNum结构体里面 BigNum ToNum(char *s) { int i, j; BigNum a; a.len = strlen(s); for(i = 0, j = a.len-1; s[i] != '\0'; i++, j--) a.num[i] = s[j]-'0'; return a; } void Init(BigNum &a, char *s, int &tag) //将字符串转化为大数 { int i = 0, j = strlen(s); if(s[0] == '-') { j--; i++; tag *= -1; } a.len = j; for(; s[i] != '\0'; i++, j--) a.num[j-1] = s[i]-'0'; } int main(void) { BigNum a, b; char s1[100], s2[100]; while(scanf("%s %s", s1, s2) != EOF) { int tag = 1; Init(a, s1, tag); //将字符串转化为大数 Init(b, s2, tag); a = Mul2(a, b); if(a.len == 1 && a.num[0] == 0) { puts("0"); } else { if(tag < 0) putchar('-'); print(a); } } return 0; }
这是原文链接blog.csdn.net/hackbuteer1/article/details/6595901
UVA上有几道高精度题目,总结如下。
uva424为大数加法
#include <iostream> #include<cstdio> #include<string.h> using namespace std; const int maxn=1<<15; struct bignum { int num[maxn]; int len; }; void tonum(char *s,bignum &a) { int len=strlen(s); a.len=len; int i,j; for(i=0,j=len-1;j>=0;j--,i++) a.num[i]=s[j]-'0'; } bignum add(bignum &a,bignum &b) { int len=(a.len>b.len)?a.len:b.len; bignum c; memset(c.num,0,sizeof(c.num)); int i; for(i=0;i<len;i++) { c.num[i]+=(a.num[i]+b.num[i]); if(c.num[i]>=10) { c.num[i]-=10; c.num[i+1]++; } } if(c.num[len]) len++; c.len=len; return c; } void PRINT(bignum a) { int i; for(i=a.len-1;i>=0;i--) printf("%d",a.num[i]); printf("\n"); } int main() { //freopen("test.txt","r",stdin); char s[110]; bignum a; a.len=1; memset(a.num,0,sizeof(a.num)); while(scanf("%s",s)!=EOF) { if(s[0]=='0') break; bignum b; tonum(s,b); a=add(a,b); } PRINT(a); return 0; }
uva10106为大数乘法
#include <iostream> #include<cstdio> #include<string.h> using namespace std; const int maxn=1<<15; struct bignum { int num[maxn]; int len; }; char s1[maxn],s2[maxn]; void tonum(char *s,bignum &a) { a.len=strlen(s); int i,j; for(i=0,j=a.len-1;j>=0;j--,i++) a.num[i]=s[j]-'0'; } bignum MUL(bignum &a,bignum &b) { bignum c; memset(c.num,0,sizeof(c.num)); int i,j,len; for(i=0;i<a.len;i++) { for(j=0;j<b.len;j++) { c.num[i+j]+=(a.num[i]*b.num[j]); if(c.num[i+j]>=10) { c.num[i+j+1]+=c.num[i+j]/10; c.num[i+j]%=10; } } } len=a.len+b.len-1; while(c.num[len-1]==0&&len>1) len--; if(c.num[len]) len++; c.len=len; return c; } void PRINT(bignum &a) { int i; for(i=a.len-1;i>=0;i--) printf("%d",a.num[i]); printf("\n"); } int main() { while(scanf("%s%s",s1,s2)!=EOF) { bignum a,b,c; tonum(s1,a); tonum(s2,b); c=MUL(a,b); PRINT(c); } return 0; }
uva748是大数求幂
#include <iostream> #include<cstdio> #include<string.h> using namespace std; const int maxn=1<<10; int main() { //freopen("test.txt","r",stdin); char R[6]; int n; while(scanf("%s%d",R,&n)!=EOF) { int s[6],point; int i,j; for(i=0,j=0;i<6;i++) { if(R[i]=='.') point=i; else s[j++]=(int)(R[i]-'0'); } point=(5-point)*n-1; //point记录小数点所在位 int src=s[0]*10000+s[1]*1000+s[2]*100+s[3]*10+s[4]; int f[maxn]; memset(f,0,sizeof(f)); f[0]=1; int t,c; for(i=1;i<=n;i++) { c=0; for(j=0;j<maxn;j++) { t=f[j]*src+c; f[j]=t%10; c=t/10; } } int flag=-1; //需要把小数后面的0消去,需记录小数点后从末端数起有几个连续的零 for(i=0;i<=maxn;i++) { if(f[i]) break; flag=i; } if(flag>point) flag=point; for(j=maxn-1;j>=0;j--) //消去前面的0 { if(j<=point) { if(f[j]) break; else { printf(j==point?".0":"0"); } } if(f[j]) { break; } } for(i=j;i>=0&&i>flag;i--) printf(i==point?".%d":"%d",f[i]); printf("\n"); } return 0; }
uva10494是大数除法
#include <iostream> #include<stdio.h> #include<string.h> using namespace std; const int maxn=1<<15; char s[maxn]; struct bignum { int num[maxn]; int len; }; void PRINT(bignum &a) { int i; for(i=a.len-1;i>=0;i--) printf("%d",a.num[i]); printf("\n"); } void div1(bignum &a,long long &b,bignum &c,long long &f) { int i,len=a.len; memset(c.num,0,sizeof(c.num)); f=0; for(i=a.len-1;i>=0;i--) { f=f*10+a.num[i]; c.num[i]=f/b; f%=b; } while(len>1&&c.num[len-1]==0) len--; c.len=len; } int main() { //freopen("test.txt","r",stdin); long long b; char op[2]; while(scanf("%s%s%lld",s,op,&b)!=EOF) { bignum a; a.len=strlen(s); int i,j=0; for(i=a.len-1;s[j]!='\0';i--,j++) a.num[j]=s[i]-'0'; bignum c; long long f; div1(a,b,c,f); if(op[0]=='/') { PRINT(c); } else { printf("%lld\n",f); } } return 0; }