高精度模板 支持各种运算 c++
绪言
自从有了高精度模板,妈妈再也不用怕我不会打高精度了!
代码
代码长度与日俱增啊~~~
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 7 bool insigma(char ch){ 8 return ch=='-'||('0'<=ch&&ch<='9'); 9 } 10 11 const int maxn = 1000; 12 struct number{ 13 int num[maxn]; 14 int len; 15 bool fu; 16 17 number(){//初始化 18 len=fu=0; 19 memset(num,0,sizeof(num)); 20 } 21 22 int updata_len(){//更新长度 23 for(int i=maxn-1;i>=0;i--) if(num[i]) return len=i+1; 24 return len=0; 25 } 26 27 // /* 28 number operator= (int x){//隐式转换 29 fu=(x<0); 30 num[0]=abs(x); 31 if(x>9) carry_bit(); 32 if(x<-9) back_space(); 33 return *this; 34 } 35 // */ 36 /* 37 number (int x){//有bug的构造函数 暂时用重载=替代 38 fu=(x<0); 39 num[0]=abs(x); 40 if(x>9) carry_bit(); 41 if(x<-9) back_space(); 42 } 43 */ 44 45 void input(){ 46 // /* 47 string a; 48 cin>>a; 49 if(a[0]=='-'){ 50 fu=1; 51 len=a.size()-1; 52 for(unsigned int i=0;i<a.size()-1;i++) num[i]=a[a.size()-i-1]-'0'; 53 } 54 else{ 55 len=a.size(); 56 for(unsigned int i=0;i<a.size();i++) num[i]=a[a.size()-i-1]-'0'; 57 } 58 59 // */ 60 /* 61 len=0; 62 char ch; 63 while(!insigma(ch=getchar())); 64 if(ch=='-') 65 fu=true; 66 else 67 num[len++]=ch-'0'; 68 while(isdigit(ch=getchar())){ 69 num[len++]=ch-'0'; 70 } 71 int t; 72 for(int i=0;i<len;i++) 73 { 74 t=num[i]; 75 num[i]=num[len-i-1]; 76 num[len-i-1]=t; 77 } 78 */ 79 } 80 81 void output(){ 82 if(fu) cout<<"-"; 83 bool flag=0; 84 for(int i=len;i>0;i--){ 85 if(num[i]) flag=1; 86 if(num[i]>9) carry_bit(); 87 if(flag) putchar(num[i]+'0');//putchar加速 88 } 89 putchar(num[0]+'0'); 90 } 91 92 friend istream & operator>> (istream &in, number &obj); 93 friend ostream & operator<< (ostream &out, number &obj); 94 95 int compare(number x){//2= 1> 0< 96 if(fu^x.fu){ 97 if(fu) return 0; 98 else return 1; 99 } 100 for(int i=max(len,x.len);i>=0;i--) 101 { 102 if(num[i]>x.num[i]) return !fu;//大于 (1) 103 if(num[i]<x.num[i]) return fu;//小于 (0) 104 } 105 return 2;//相等 106 } 107 108 //利用compare()重载比较运算符 109 110 bool operator> (number x){ 111 return (compare(x)==1); 112 } 113 114 bool operator< (number x){ 115 return (compare(x)==0); 116 } 117 118 bool operator>= (number x){ 119 return !(*this<x); 120 } 121 122 bool operator<= (number x){ 123 return !(*this>x); 124 } 125 126 bool operator== (number x){ 127 return compare(x)==2; 128 } 129 130 bool operator!= (number x){ 131 return compare(x)!=2; 132 } 133 134 number operator++ (){ 135 num[0]++; 136 if(num[0]>9) carry_bit(); 137 return *this; 138 } 139 140 number operator++ (int){ 141 number save=*this; 142 ++*this; 143 return save; 144 } 145 146 number operator-- (){ 147 num[0]--; 148 if(num[0]<0) back_space(); 149 return *this; 150 } 151 152 number operator-- (int){ 153 number save=*this; 154 num[0]--; 155 if(num[0]<0) back_space(); 156 return save; 157 } 158 159 bool judge_zero(){ 160 for(int i=maxn-1;i>=0;i--) 161 if(num[i]) return 0; 162 return 1; 163 } 164 165 bool judge_non_zero(){ 166 return !judge_zero(); 167 } 168 169 bool convert_bool(){ 170 return !judge_zero(); 171 } 172 173 bool even(){ 174 if(num[0]%2) return 0; 175 return 1; 176 } 177 178 bool odd(){ 179 if(num[0]%2) return 1; 180 return 0; 181 } 182 183 void carry_bit(){ 184 for(int i=0;i<maxn;i++){ 185 num[i+1]+=num[i]/10; 186 num[i]%=10; 187 } 188 updata_len(); 189 } 190 191 void back_space(){ 192 for(int i=0;i<maxn;i++){ 193 while(num[i]<0) num[i]+=10,num[i+1]--; 194 } 195 } 196 197 number operator+ (int x){ 198 number newness=*this; 199 newness.num[0]+=x; 200 if(newness.num[0]>9) newness.carry_bit(); 201 return newness; 202 } 203 204 number operator+ (number x){ 205 number res=x; 206 for(int i=0;i<maxn;i++) 207 { 208 res.num[i]+=num[i]; 209 } 210 res.carry_bit(); 211 return res; 212 } 213 214 number operator+= (int x){ 215 *this=(*this+x); 216 return *this; 217 } 218 219 number operator+= (number x){ 220 *this=*this+x; 221 return *this; 222 } 223 224 number operator- (number x){ 225 number i,j; 226 if(compare(x)) {i=*this,j=x;} 227 else {i=x,j=*this;} 228 for(int t=0;t<maxn;t++) 229 { 230 i.num[t]-=j.num[t]; 231 } 232 i.back_space(); 233 return i; 234 } 235 236 number operator-= (number x){ 237 *this=*this-x; 238 return *this; 239 } 240 241 number operator* (number x){ 242 number sum; 243 sum.fu=fu^x.fu; 244 for(int i=0;i<updata_len();i++) 245 for(int j=0;j<x.updata_len();j++) 246 { 247 if(i+j>maxn-1) continue; 248 sum.num[i+j]+=num[i]*x.num[j]; 249 } 250 sum.carry_bit(); 251 return sum; 252 } 253 254 number operator*= (number x){ 255 return *this=*this*x; 256 } 257 258 number factor(){ 259 number ans,t; 260 t.num[0]=1; 261 ans.num[0]=1; 262 for(;t<=*this;t.num[0]+=1,t.carry_bit()) 263 ans*=t; 264 return ans; 265 } 266 267 number division2(){ 268 for(int i=maxn-1;i>=0;i--){ 269 if(num[i]&1&&i!=0) num[i-1]+=10; 270 num[i]>>=1; 271 } 272 return *this; 273 } 274 }; 275 276 istream & operator>> (istream &in, number &obj) 277 { 278 string a; 279 in>>a; 280 if(a[0]=='-'){ 281 obj.fu=1; 282 obj.len=a.size()-1; 283 for(unsigned int i=0;i<a.size()-1;i++) obj.num[i]=a[a.size()-i-1]-'0'; 284 } 285 else{ 286 obj.len=a.size(); 287 for(unsigned int i=0;i<a.size();i++) obj.num[i]=a[a.size()-i-1]-'0'; 288 } 289 if (!in) obj = number(); 290 return in; 291 } 292 293 ostream & operator<< (ostream &out, number &obj) 294 { 295 if(obj.fu) cout<<"-"; 296 bool flag=0; 297 for(int i=obj.len;i>0;i--){ 298 if(obj.num[i]) flag=1; 299 if(obj.num[i]>9) obj.carry_bit(); 300 if(flag) out<<obj.num[i]; 301 } 302 out<<obj.num[0]; 303 return out; 304 } 305 306 307 number gcd_rec(number a,number b){ 308 if(b.judge_zero()) return a; 309 return gcd_rec(b,a-b); 310 } 311 312 number gcd(number a,number b){ 313 if(a.judge_zero()) return a; 314 number t; 315 for(;;t=b,b=a-b,a=t) 316 if(b.judge_zero()) return a; 317 return a; 318 } 319 320 number power(number a,number n){ 321 number zero; 322 number c;c=1; 323 for(;n>zero;n.division2(),a*=a) if(n.odd()) c*=a; 324 return c; 325 } 326 327 int main() 328 { 329 freopen("gcd.in","r",stdin); 330 freopen("gcd.out","w",stdout); 331 number a,b,c; 332 cin>>a>>b; 333 c=gcd(a,b); 334 cout<<c; 335 return 0; 336 }
更新日志
其实我是在写了300行以后才来写这篇博客的,所以之前的时间点就不计了吧!
(2019-11-05ago)
加法
进位
构造
比较
减法
退位
递归求gcd
非递归gcd
乘法
阶乘
iostream
除以2
判断奇偶
快速幂
……
细节实现
相信这里有许多我(以前)不会的c++语言用法吧。我把它们都记录下来了呢!
构造函数
当我们定义一个number时,由于可能是局部变量,我们就要先将其赋初值
但是number不是int,不是double,要是我们要赋初值的话,还得将其所有的变量(even arraies!)赋初值!
所以我为了在使用number时方便,在网上找了个东西叫做 构造函数
函数与结构体(或类,一下省略)同名,没有返回值(不是void!)
在新定义一个number时会自动调用
作用大概就是 赋初值 吧
(PS:还有个函数叫 析构函数,用于释放结构体内存时操作(例如:删除指针等),有兴趣可以去看看)
number(){ len=fu=0; memset(num,0,sizeof(num)); }
但要是我们要给一个number赋初值怎么办?
一个即将退役的老OIer告诉我,再来一个构造函数,但是它是要传参的呗!
但是,由于我不会用,只好重载的=(赋值运算符)来赋初值。
number operator= (int x){//隐式转换(?) fu=(x<0); num[0]=abs(x); if(x>9) carry_bit(); if(x<-9) back_space(); return *this; }
也许以后我就会用了吧!
重载前缀自增自减运算符
本来我想到了自增自减有前缀和后缀之分,但是不知道该怎么打……
所以就先打了个不知道是哪种的operator+
number operator++ (){ num[0]++; if(num[0]>9) carry_bit(); return *this; }
结果发现只有前缀才能用。
那么后缀的该怎么打呢?
重载后缀自增自减运算符
几番查找后,终于在《C++ Primer Plus》里面找到了
只要在()里加一个int即可
(原理不知)
number operator++ (int){ number save=*this; ++*this; return save; }
这里我甚至还偷懒地在后缀里用了前缀……本来就没错嘛!
重载赋值运算符(int转num高精度)
见 构造函数 末尾部分
number operator= (int x){//隐式转换 fu=(x<0); num[0]=abs(x); if(x>9) carry_bit(); if(x<-9) back_space(); return *this; }
重载输入输出流运算符(友元)
首先我为了输入输出各自写了一个成员函数
void input(){ string a; cin>>a; if(a[0]=='-'){ fu=1; len=a.size()-1; for(unsigned int i=0;i<a.size()-1;i++) num[i]=a[a.size()-i-1]-'0'; } else{ len=a.size(); for(unsigned int i=0;i<a.size();i++) num[i]=a[a.size()-i-1]-'0'; } }
void output(){ if(fu) cout<<"-"; bool flag=0; for(int i=len;i>0;i--){ if(num[i]) flag=1; if(num[i]>9) carry_bit(); if(flag) putchar(num[i]+'0');//putchar加速 } putchar(num[0]+'0'); }
后来,我想:看看人家STL-string,都可以直接拿cin cout输入输出了,你怎么就不可以做到呢?
我又去网上,书中找了找怎么重载流运算符……
不想讲了,就是套模板,把之前写的那个input和output套进去就可以了嘛!
But,由于stream是一个已经封装好了的类,你也不能修改头文件中的内容,怎么办呢?
answer:用友元!它可以“打入敌人内部”进行一些操作!
友元函数声明(要放在结构体中!)
friend istream & operator>> (istream &in, number &obj); friend ostream & operator<< (ostream &out, number &obj);
即 在正常的函数前加上friend即可
友元函数定义(要放在全局中!)
istream & operator>> (istream &in, number &obj) { string a; in>>a; if(a[0]=='-'){ obj.fu=1; obj.len=a.size()-1; for(unsigned int i=0;i<a.size()-1;i++) obj.num[i]=a[a.size()-i-1]-'0'; } else{ obj.len=a.size(); for(unsigned int i=0;i<a.size();i++) obj.num[i]=a[a.size()-i-1]-'0'; } if (!in) obj = number(); return in; } ostream & operator<< (ostream &out, number &obj) { if(obj.fu) cout<<"-"; bool flag=0; for(int i=obj.len;i>0;i--){ if(obj.num[i]) flag=1; if(obj.num[i]>9) obj.carry_bit(); if(flag) out<<obj.num[i]; } out<<obj.num[0]; return out; }
重载判断符运算符
那么多比较函数,我一下子那写的过来呢?
本来我都是没有operator这些比较运算符的,只用了一个int compare(number)就好了
PS:为什么返回值不是bool而是int呢?因为返回的信息可能不只有大于,小于,还会有等于呀!
int compare(number x){//2= 1> 0< if(fu^x.fu){ if(fu) return 0; else return 1; } for(int i=max(len,x.len);i>=0;i--) { if(num[i]>x.num[i]) return !fu;//大于 (1) if(num[i]<x.num[i]) return fu;//小于 (0) } return 2;//相等 }
后来,我觉得这样十分的不直观,而且有时容易错,还是个成员函数,调用时是a.compare(b)这样的形式的……
所以我就把"<",">","<=",">=","==","!="都重载了!
Impression
现在的长度是有限的而且在枚举时也可能会有大量时间浪费
尽管已经引进了len和updata_len(),但是这两个玩意的作用还是较小,用法比较麻烦
希望能像STL的某些容器那样可自动改变大小,已经O(1)就可以知道number的位数
不知道为什么,一个number表达式不可以用cout<<输出?
就像
a,b为number时,cout<<(a+b);不可以;
但是
a,b为int时,cout<<(a+b);可以!
是因为operator<< 里的参数obj为引用吗?
除法(二分)
这个玩意还有存在许多许多可以更新&改进的地方,欢迎提建议!