为什么本文的标题要强调十进制形式呢?因为还有万进制的高精度,比十进制要快很多
那我们直接掌握万进制不就好了嘛。。其实不然,十进制高精度的实现是最直接的对加减乘除的模拟,并且其中的实现方法也是值得去借鉴的
这里在刘汝佳代码的基础上进行了一定的改进,经过了若干次测试形成了稳定版本,在对效率要求比较高的情况下,建议替换为万进制高精度
首先给出结构体中的元素:
int len,s[maxn]; bign() //构造函数 { len=1; memset(s,0,sizeof(s)); }
注意,这里的s数组是倒着存数字的,为了便于计算
接下来我们罗列几个运算符重载和工具函数,目的在注释中体现:
bign(const int num) //bign x=100; { *this=num; } bign(const char* num) //bign x="100"; { *this=num; } bign operator =(const int num) //x=1234; { char s[maxn]; sprintf(s,"%d",num); *this=s; return *this; } bign operator =(const char* num) //x="1234"; { len=strlen(num); for(int i=0;i<len;i++) s[i]=num[len-i-1]-'0'; return *this; } string str() const //成员函数,用于输出 { string res=""; for(int i=0;i<len;i++) res=(char)(s[i]+'0')+res; if(res=="") res="0"; return res; } void clean() //成员函数,用于清除前导0 { while(len>1&&!s[len-1]) //当前长度>1并且当前位是0 len--; }
紧接着是加减法的实现,他们放在一起是因为他们都包含一个变量g,这里的g用来表示进位或者是借位的位数
bign operator +(const bign& b) const { bign c; c.len=0; for(int i=0,g=0;g||i<max(len,b.len);i++) { int x=g; if(i<len) x+=s[i]; if(i<b.len) x+=b.s[i]; c.s[c.len++]=x%10; g=x/10; } return c; } bign operator -(const bign& b) const { bign c; c.len=0; for(int i=0,g=0;i<len;i++) { int x=s[i]-g; if(i<b.len) x-=b.s[i]; if(x>=0) g=0; else { g=1; x+=10; } c.s[c.len++]=x; } c.clean(); return c; }
然后是乘法,掌握乘法只要掌握两个乘数和积之间下标的关系就好了(s[i+j])
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; }
然后我们罗列一些比较运算符的重载,除法搁在后面的原因是要用到这些重载形式,比较大小的重载逻辑是显然的。
bool operator <(const bign& b) const { if(len!=b.len) return len<b.len; //先比位数 for(int i=len-1;i>=0;i--) // if(s[i]!=b.s[i]) return s[i]<b.s[i]; //再比最高位 } bool operator >(const bign& b) const { if(len!=b.len) return len>b.len; //先比位数 for(int i=len-1;i>=0;i--) // if(s[i]!=b.s[i]) return s[i]>b.s[i]; //再比最高位 } bool operator ==(const bign& b) const { return !(*this>b)&&!(*this<b); } bool operator >=(const bign& b) const { return *this>b||*this==b; }
对于除法的重载,我们采用的是一位一位减,当然可以使用二分法,二分法的形式后期可能会加以补充
bign operator /(const bign &b) const { bign c,f=0; for(int i=len-1;i>=0;i--) { f=f*10; f.s[0]=s[i]; while(f>=b) { f=f-b; c.s[i]++; } } c.len=len; c.clean(); return c; }
接下来重载<<和>>运算符来支持cin和cout
istream &operator >>(istream &in,bign& x) //重载输入 { string s; in>>s; x=s.c_str(); return in; } ostream & operator <<(ostream & out,const bign& x) //重载输出 { out<<x.str(); return out; }
最后给出完整模板,大部分的题目都要求结果去模一个数,高精度的用武之地很少了,只能出现在OI的部分分中,ACM中很少出现
除非将一些类似于表达式求值或者是矩阵快速幂等一些复杂的模拟形式与之相结合。。。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<string> 6 using namespace std; 7 const int maxn=505; 8 struct bign 9 { 10 int len,s[maxn]; 11 bign() //构造函数 12 { 13 len=1; 14 memset(s,0,sizeof(s)); 15 } 16 bign(const int num) //bign x=100; 17 { 18 *this=num; 19 } 20 bign(const char* num) //bign x="100"; 21 { 22 *this=num; 23 } 24 bign operator =(const int num) //x=1234; 25 { 26 char s[maxn]; 27 sprintf(s,"%d",num); 28 *this=s; 29 return *this; 30 } 31 bign operator =(const char* num) //x="1234"; 32 { 33 len=strlen(num); 34 for(int i=0;i<len;i++) 35 s[i]=num[len-i-1]-'0'; 36 return *this; 37 } 38 string str() const //成员函数,用于输出 39 { 40 string res=""; 41 for(int i=0;i<len;i++) 42 res=(char)(s[i]+'0')+res; 43 if(res=="") res="0"; 44 return res; 45 } 46 void clean() //成员函数,用于清除前导0 47 { 48 while(len>1&&!s[len-1]) //当前长度>1并且当前位是0 49 len--; 50 } 51 bign operator +(const bign& b) const 52 { 53 bign c; 54 c.len=0; 55 for(int i=0,g=0;g||i<max(len,b.len);i++) 56 { 57 int x=g; 58 if(i<len) x+=s[i]; 59 if(i<b.len) x+=b.s[i]; 60 c.s[c.len++]=x%10; 61 g=x/10; 62 } 63 return c; 64 } 65 bign operator -(const bign& b) const 66 { 67 bign c; 68 c.len=0; 69 for(int i=0,g=0;i<len;i++) 70 { 71 int x=s[i]-g; 72 if(i<b.len) x-=b.s[i]; 73 if(x>=0) g=0; 74 else 75 { 76 g=1; 77 x+=10; 78 } 79 c.s[c.len++]=x; 80 } 81 c.clean(); 82 return c; 83 } 84 bign operator *(const bign& b) const 85 { 86 bign c; 87 c.len=len+b.len; //最大总位数 88 for(int i=0;i<len;i++) 89 for(int j=0;j<b.len;j++) 90 c.s[i+j]+=s[i]*b.s[j]; //枚举出每一位 91 for(int i=0;i<c.len-1;i++) 92 { 93 c.s[i+1]+=c.s[i]/10; //进位 94 c.s[i]%=10; //当前位 95 } 96 c.clean(); 97 return c; 98 } 99 bool operator <(const bign& b) const 100 { 101 if(len!=b.len) return len<b.len; //先比位数 102 for(int i=len-1;i>=0;i--) // 103 if(s[i]!=b.s[i]) return s[i]<b.s[i]; //再比最高位 104 } 105 bool operator >(const bign& b) const 106 { 107 if(len!=b.len) return len>b.len; //先比位数 108 for(int i=len-1;i>=0;i--) // 109 if(s[i]!=b.s[i]) return s[i]>b.s[i]; //再比最高位 110 } 111 bool operator ==(const bign& b) const 112 { 113 return !(*this>b)&&!(*this<b); 114 } 115 bool operator >=(const bign& b) const 116 { 117 return *this>b||*this==b; 118 } 119 bign operator /(const bign &b) const 120 { 121 bign c,f=0; 122 for(int i=len-1;i>=0;i--) 123 { 124 f=f*10; 125 f.s[0]=s[i]; 126 while(f>=b) 127 { 128 f=f-b; 129 c.s[i]++; 130 } 131 } 132 c.len=len; 133 c.clean(); 134 return c; 135 } 136 }; 137 istream &operator >>(istream &in,bign& x) //重载输入 138 { 139 string s; 140 in>>s; 141 x=s.c_str(); 142 return in; 143 } 144 ostream & operator <<(ostream & out,const bign& x) //重载输出 145 { 146 out<<x.str(); 147 return out; 148 } 149 int main() 150 { 151 bign a,b; 152 cin>>a>>b; 153 cout<<a/b; 154 return 0; 155 }