绪言
自从有了高精度模板,妈妈再也不用怕我不会打高精度了!
代码
代码长度与日俱增啊~~~

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为引用吗?
除法(二分)
这个玩意还有存在许多许多可以更新&改进的地方,欢迎提建议!
