Nhảy chuyển đến

Cao độ chặt chẽ tính toán

Quá dài không xem bản: Kết cục tự rước khuôn mẫu……

Định nghĩa

Cao độ chặt chẽ tính toán ( Arbitrary-Precision Arithmetic ), cũng bị gọi đại số nguyên ( bignum ) tính toán, vận dụng một ít thuật toán kết cấu tới duy trì lớn hơn nữa số nguyên gian giải toán ( con số lớn nhỏ vượt qua ngôn ngữ nội kiến chỉnh hình ).

Dẫn vào

Cao độ chặt chẽ vấn đề bao hàm rất nhiều tiểu nhân chi tiết, thực hiện thượng cũng có rất nhiều chú trọng.

Cho nên hôm nay liền tới cùng nhau thực hiện một cái đơn giản tính toán khí đi.

Nhiệm vụ

Đưa vào: Một cái hình nhưa &LTop> bBiểu đạt thức.

  • a,bPhân biệt là chiều dài không vượt quaSố thập phân phi phụ số nguyên;
  • &LTop>Là một chữ phù (+,-,*Hoặc/), tỏ vẻ giải toán.
  • Số nguyên cùng giải toán phù chi gian từ một cái không cách phân cách.

Phát ra: Giải toán kết quả.

  • Đối với+,-,*Giải toán, phát ra một hàng tỏ vẻ kết quả;
  • Đối với/Giải toán, phát ra hai hàng phân biệt tỏ vẻ thương cùng số dư.
  • Bảo đảm kết quả đều vì phi phụ số nguyên.

Tồn trữ

Ở bình thường thực hiện trung, cao độ chặt chẽ con số lợi dụng tự phù xuyến tỏ vẻ, mỗi một chữ phù tỏ vẻ con số một cái số thập phân vị. Bởi vậy có thể nói, cao độ chặt chẽ trị số tính toán trên thực tế là một loại đặc biệt tự phù xuyến xử lý.

Đọc nhập tự phù xuyến khi, con số tối cao vị ở tự phù xuyến đầu ( hạ tiêu tiểu nhân vị trí ). Nhưng là thói quen thượng, hạ tiêu nhỏ nhất vị trí gửi chính là con sốThấp nhất vị,Tức tồn trữ xoay ngược lại tự phù xuyến. Làm như vậy nguyên nhân ở chỗ, con số chiều dài khả năng phát sinh biến hóa, nhưng chúng ta hy vọng đồng dạng quyền giá trị vị trước sau bảo trì đối tề ( tỷ như, hy vọng sở hữu hàng đơn vị đều tại hạ tiêu[0],Sở hữu mười vị đều tại hạ tiêu[1]…… ); đồng thời, thêm, giảm, thừa giải toán giống nhau đều từ hàng đơn vị bắt đầu tiến hành ( hồi tưởng tiểu học dựng thức giải toán ), này đều cho “Xoay ngược lại tồn trữ” lấy nguyên vẹn lý do.

Từ nay về sau chúng ta đem vẫn luôn tiếp tục sử dụng này một ước định. Định nghĩa một cái hằng sốLEN = 1004Tỏ vẻ trình tự sở cất chứa lớn nhất chiều dài.

Bởi vậy không khó viết ra đọc nhập cao độ chặt chẽ con số số hiệu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
voidclear(inta[]){
for(inti=0;iLEN;++i)a[i]=0;
}

voidread(inta[]){
staticchars[LEN+1];
scanf("%s",s);

clear(a);

intlen=strlen(s);
// như trên sở thuật, xoay ngược lại
for(inti=0;ilen;++i)a[len-i-1]=s[i]-'0';
// s[i] - '0' chính là s[i] sở tỏ vẻ chữ số
// có chút đồng học khả năng càng thói quen dùng ord(s[i]) - ord('0') phương thức lý giải
}

Phát ra cũng dựa theo tồn trữ nghịch tự phát ra. Bởi vì không hy vọng phát ra dẫn đường linh, cố nơi này từ tối cao vị bắt đầu xuống phía dưới tìm kiếm cái thứ nhất phi linh vị, từ nơi này bắt đầu phát ra; ngưng hẳn điều kiệni >= 1Mà không phảii >= 0Là bởi vì đương toàn bộ con số tương đươngKhi vẫn hy vọng phát ra một chữ phù0.

1
2
3
4
5
6
7
voidprint(inta[]){
inti;
for(i=LEN-1;i>=1;--i)
if(a[i]!=0)break;
for(;i>=0;--i)putchar(a[i]+'0');
putchar('\n');
}

Hợp lại chính là một cái hoàn chỉnh máy đọc lại trình tự lạc.

copycat.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include&LTcstdio>
#include&LTcstring>

staticconstintLEN=1004;

inta[LEN],b[LEN];

voidclear(inta[]){
for(inti=0;iLEN;++i)a[i]=0;
}

voidread(inta[]){
staticchars[LEN+1];
scanf("%s",s);

clear(a);

intlen=strlen(s);
for(inti=0;ilen;++i)a[len-i-1]=s[i]-'0';
}

voidprint(inta[]){
inti;
for(i=LEN-1;i>=1;--i)
if(a[i]!=0)break;
for(;i>=0;--i)putchar(a[i]+'0');
putchar('\n');
}

intmain(){
read(a);
print(a);

return0;
}

Bốn phép tính giải toán

Bốn phép tính giải toán trung khó khăn cũng các không giống nhau. Đơn giản nhất chính là cao độ chặt chẽ phép cộng trừ, tiếp theo là cao độ chặt chẽ — đơn độ chặt chẽ ( bình thườngint) phép nhân cùng cao độ chặt chẽ — cao độ chặt chẽ phép nhân, cuối cùng là cao độ chặt chẽ — cao độ chặt chẽ phép chia.

Chúng ta đem ấn cái này trình tự phân biệt thực hiện sở hữu yêu cầu công năng.

Toán cộng

Cao độ chặt chẽ toán cộng, kỳ thật chính là dựng thức toán cộng lạp.

Cũng chính là từ thấp nhất vị bắt đầu, đem hai cái số cộng đối ứng vị trí thượng chữ số tương thêm, cũng phán đoán hay không đạt tới hoặc vượt qua.Nếu đạt tới, như vậy xử lý tiến vị: Đem càng cao một vị kết quả thượng gia tăng,Trước mặt vị kết quả giảm bớt.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
voidadd(inta[],intb[],intc[]){
clear(c);

// cao độ chặt chẽ thực hiện trung, giống nhau lệnh số tổ lớn nhất chiều dài LEN so khả năng đưa vào lớn hơn một chút
// sau đó bỏ bớt đi cuối cùng vài lần tuần hoàn, cứ như vậy có thể tỉnh đi không ít biên giới tình huống xử lý
// bởi vì thực tế đưa vào sẽ không vượt qua 1000 vị, cố tại đây tuần hoàn đến LEN - 1 = 1003 đã cũng đủ
for(inti=0;iLEN-1;++i){
// đem tương ứng vị thượng chữ số tương thêm
c[i]+=a[i]+b[i];
if(c[i]>=10){
// tiến vị
c[i+1]+=1;
c[i]-=10;
}
}
}

Thử cùng thượng một bộ phận kết hợp, có thể được đến một cái toán cộng tính toán khí.

adder.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include&LTcstdio>
#include&LTcstring>

staticconstintLEN=1004;

inta[LEN],b[LEN],c[LEN];

voidclear(inta[]){
for(inti=0;iLEN;++i)a[i]=0;
}

voidread(inta[]){
staticchars[LEN+1];
scanf("%s",s);

clear(a);

intlen=strlen(s);
for(inti=0;ilen;++i)a[len-i-1]=s[i]-'0';
}

voidprint(inta[]){
inti;
for(i=LEN-1;i>=1;--i)
if(a[i]!=0)break;
for(;i>=0;--i)putchar(a[i]+'0');
putchar('\n');
}

voidadd(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
c[i]+=a[i]+b[i];
if(c[i]>=10){
c[i+1]+=1;
c[i]-=10;
}
}
}

intmain(){
read(a);
read(b);

add(a,b,c);
print(c);

return0;
}

Phép trừ

Cao độ chặt chẽ phép trừ, cũng chính là dựng thức phép trừ lạp.

Từ hàng đơn vị khởi trục vị tương giảm, gặp được phụ tình huống tắc hướng về phía trước một vị mượn.Chỉnh thể ý nghĩ cùng toán cộng hoàn toàn nhất trí.

1
2
3
4
5
6
7
8
9
10
11
12
13
voidsub(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
// trục vị tương giảm
c[i]+=a[i]-b[i];
if(c[i]0){
// tá vị
c[i+1]-=1;
c[i]+=10;
}
}
}

Đem thượng một cái trình tự trungadd()Thay đổi thànhsub(),Liền có một cái phép trừ tính toán khí.

subtractor.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include&LTcstdio>
#include&LTcstring>

staticconstintLEN=1004;

inta[LEN],b[LEN],c[LEN];

voidclear(inta[]){
for(inti=0;iLEN;++i)a[i]=0;
}

voidread(inta[]){
staticchars[LEN+1];
scanf("%s",s);

clear(a);

intlen=strlen(s);
for(inti=0;ilen;++i)a[len-i-1]=s[i]-'0';
}

voidprint(inta[]){
inti;
for(i=LEN-1;i>=1;--i)
if(a[i]!=0)break;
for(;i>=0;--i)putchar(a[i]+'0');
putchar('\n');
}

voidsub(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
c[i]+=a[i]-b[i];
if(c[i]0){
c[i+1]-=1;
c[i]+=10;
}
}
}

intmain(){
read(a);
read(b);

sub(a,b,c);
print(c);

return0;
}

Thử một lần, đưa vào1 2—— phát ra/9999999,Ai cái nàyOI WikiNhư thế nào cho ta một phần giả số hiệu a……

Trên thực tế, mặt trên số hiệu chỉ có thể xử lý số trừLớn hơn hoặc bằng số bị trừTình huống. Xử lý số bị trừ so số trừ tiểu, tứcKhi tình huống rất đơn giản.

Muốn tính toánGiá trị, bởi vì có,Có thể thuyên chuyển trở lên số hiệu trungsubHàm số, phương pháp sáng tác vìsub(b,a,c).Phải được đếnGiá trị, ở đáp số trước hơn nữa dấu trừ là được.

Phép nhân

Cao độ chặt chẽ — đơn độ chặt chẽ

Cao độ chặt chẽ phép nhân, cũng chính là dựng…… Đợi chút đợi chút!

Trước suy xét một cái đơn giản tình huống: Số nhân trung một cái là bình thườngintLoại hình. Có hay không đơn giản xử lý phương pháp đâu?

Một cái trực quan ý nghĩ là trực tiếp đemMỗi một vị thượng con số thừa lấy.Từ trị số đi lên nói, phương pháp này là chính xác, nhưng nó cũng không phù hợp số thập phân tỏ vẻ pháp, bởi vậy yêu cầu đem nó một lần nữa sửa sang lại thành bình thường bộ dáng.

Trọng chỉnh phương thức, cũng là từ hàng đơn vị bắt đầu trục vị hướng về phía trước xử lý tiến vị. Nhưng là nơi này tiến vị khả năng phi thường đại, thậm chí rộng lớn với,Bởi vì mỗi một vị bị thừa thượng lúc sau đều khả năng đạt tớiSố lượng cấp. Cho nên nơi này tiến vị không thể lại đơn giản mà tiến hànhGiải toán, mà là muốn thông qua trừ lấyThương cùng với số dư tính toán. Tường thấy số hiệu chú thích, cũng có thể tham khảo hạ đồ triển lãm một cái tính toán cao độ chặt chẽ sốThừa lấy đơn độ chặt chẽ sốQuá trình.

Đương nhiên, cũng là xuất phát từ nguyên nhân này, phương pháp này yêu cầu đặc biệt chú ý số nhânPhạm vi. Nếu nó cùng( hoặc tương ứng chỉnh hình lấy giá trị thượng giới ) thuộc về cùng số lượng cấp, như vậy yêu cầu thận dùng cao độ chặt chẽ — đơn độ chặt chẽ phép nhân.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
voidmul_short(inta[],intb,intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
// trực tiếp đem a đệ i vị chữ số thừa lấy số nhân, gia nhập kết quả
c[i]+=a[i]*b;

if(c[i]>=10){
// xử lý tiến vị
// c[i] / 10 tức phép chia thương số trở thành tiến vị tăng lượng giá trị
c[i+1]+=c[i]/10;
// mà c[i] % 10 tức phép chia số dư trở thành ở trước mặt vị lưu lại giá trị
c[i]%=10;
}
}
}

Cao độ chặt chẽ — cao độ chặt chẽ

Nếu hai cái số nhân đều là cao độ chặt chẽ, như vậy dựng thức phép nhân lại có thể thi thố tài năng.

Hồi tưởng dựng thức phép nhân mỗi một bước, trên thực tế là tính toán bao nhiêuCùng. Tỷ như tính toán,Tính toán chính là.

Vì thế có thể đemPhân giải vì nó sở hữu chữ số, trong đó mỗi cái chữ số đều là đơn độ chặt chẽ số, đem chúng nó phân biệt cùngTương thừa, lại hướng tả di động đến từng người vị trí ăn ảnh thêm tức đến đáp án. Đương nhiên, cuối cùng cũng yêu cầu dùng cùng thượng lệ tương đồng phương thức xử lý tiến vị.

Chú ý cái này quá trình cùng dựng thức phép nhân không phải đều giống nhau, chúng ta thuật toán ở mỗi một bước thừa trong quá trình cũng không tiến vị, mà là đem sở hữu kết quả giữ lại ở đối ứng vị trí thượng, đến cuối cùng lại thống nhất xử lý tiến vị, nhưng này sẽ không ảnh hưởng kết quả.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
voidmul(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
// nơi này trực tiếp tính toán kết quả trung từ thấp đến cao đệ i vị, thả cùng nhau xử lý tiến vị
// đệ i thứ tuần hoàn vì c[i] hơn nữa sở hữu thỏa mãn p + q = i a[p] cùng b[q] tích số chi cùng
// làm như vậy hiệu quả cùng trực tiếp tiến hành thượng đồ giải toán cuối cùng cầu hòa là giống nhau, chỉ là càng thêm ngắn gọn một loại thực hiện phương thức
for(intj=0;ji;++j)c[i]+=a[j]*b[i-j];

if(c[i]>=10){
c[i+1]+=c[i]/10;
c[i]%=10;
}
}
}

Phép chia

Cao độ chặt chẽ phép chia một loại thực hiện phương thức chính là dựng thức trường phép chia.

Dựng thức trường phép chia trên thực tế có thể coi như một cái trục thứ phép trừ quá trình. Tỷ như thượng đồ trung thương số mười vị tính toán có thể như vậy lý giải: ĐemGiảm đi ba lầnSau trở nên nhỏ hơn,Không thể lại giảm, vì vậy vị vì.

Vì giảm bớt nhũng dư giải toán, chúng ta trước tiên được đến số bị chia chiều dàiCùng số chia chiều dài,Từ dưới tiêuBắt đầu, từ địa vị cao đến thấp vị tới tính toán thương. Này cùng thủ công tính toán khi đem lần đầu tiên phép nhân tối cao vị cùng số bị chia tối cao vị đối tề cách làm là giống nhau.

Tham khảo trình tự thực hiện một cái hàm sốgreater_eq()Dùng cho phán đoán số bị chia dưới tiêulast_dgVì thấp nhất vị, hay không có thể lại giảm đi số chia mà bảo trì phi phụ. Từ nay về sau đối với thương mỗi một vị, không ngừng thuyên chuyểngreater_eq(),Cũng ở thành lập thời điểm dùng cao độ chặt chẽ phép trừ từ số dư trung giảm đi số chia, cũng tức bắt chước dựng thức phép chia quá trình.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// số bị chia a dưới tiêu last_dg vì thấp nhất vị, hay không có thể lại giảm đi số chia b mà bảo trì phi phụ
// len là số chia b chiều dài, tránh cho lặp lại tính toán
boolgreater_eq(inta[],intb[],intlast_dg,intlen){
// có khả năng số bị chia còn thừa bộ phận so số chia trường, cái này dưới tình huống nhiều nhất nhiều ra 1 vị, cố như thế phán đoán có thể
if(a[last_dg+len]!=0)returntrue;
// từ địa vị cao đến thấp vị, trục vị tương đối
for(inti=len-1;i>=0;--i){
if(a[last_dg+i]>b[i])returntrue;
if(a[last_dg+i]b[i])returnfalse;
}
// bằng nhau tình hình hạ cũng là được không
returntrue;
}

voiddiv(inta[],intb[],intc[],intd[]){
clear(c);
clear(d);

intla,lb;
for(la=LEN-1;la>0;--la)
if(a[la-1]!=0)break;
for(lb=LEN-1;lb>0;--lb)
if(b[lb-1]!=0)break;
if(lb==0){
puts(">);
return;
}// số chia không thể bằng không

// c là thương
// d là số bị chia còn thừa bộ phận, thuật toán sau khi kết thúc tự nhiên trở thành số dư
for(inti=0;ila;++i)d[i]=a[i];
for(inti=la-lb;i>=0;--i){
// tính toán thương đệ i vị
while(greater_eq(d,b,i,lb)){
// nếu có thể giảm, tắc giảm
// một đoạn này là một cái cao độ chặt chẽ phép trừ
for(intj=0;jlb;++j){
d[i+j]-=b[j];
if(d[i+j]0){
d[i+j+1]-=1;
d[i+j]+=10;
}
}
// sử thương này một vị gia tăng 1
c[i]+=1;
// phản hồi tuần hoàn mở đầu, một lần nữa kiểm tra
}
}
}

Nhập Môn Thiên hoàn thành!

Đem mặt trên giới thiệu bốn phép tính giải toán thực hiện kết hợp, có thể hoàn thành mở đầu nhắc tới tính toán khí trình tự.

calculator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include&LTcstdio>
#include&LTcstring>

staticconstintLEN=1004;

inta[LEN],b[LEN],c[LEN],d[LEN];

voidclear(inta[]){
for(inti=0;iLEN;++i)a[i]=0;
}

voidread(inta[]){
staticchars[LEN+1];
scanf("%s",s);

clear(a);

intlen=strlen(s);
for(inti=0;ilen;++i)a[len-i-1]=s[i]-'0';
}

voidprint(inta[]){
inti;
for(i=LEN-1;i>=1;--i)
if(a[i]!=0)break;
for(;i>=0;--i)putchar(a[i]+'0');
putchar('\n');
}

voidadd(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
c[i]+=a[i]+b[i];
if(c[i]>=10){
c[i+1]+=1;
c[i]-=10;
}
}
}

voidsub(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
c[i]+=a[i]-b[i];
if(c[i]0){
c[i+1]-=1;
c[i]+=10;
}
}
}

voidmul(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
for(intj=0;ji;++j)c[i]+=a[j]*b[i-j];

if(c[i]>=10){
c[i+1]+=c[i]/10;
c[i]%=10;
}
}
}

boolgreater_eq(inta[],intb[],intlast_dg,intlen){
if(a[last_dg+len]!=0)returntrue;
for(inti=len-1;i>=0;--i){
if(a[last_dg+i]>b[i])returntrue;
if(a[last_dg+i]b[i])returnfalse;
}
returntrue;
}

voiddiv(inta[],intb[],intc[],intd[]){
clear(c);
clear(d);

intla,lb;
for(la=LEN-1;la>0;--la)
if(a[la-1]!=0)break;
for(lb=LEN-1;lb>0;--lb)
if(b[lb-1]!=0)break;
if(lb==0){
puts(">);
return;
}

for(inti=0;ila;++i)d[i]=a[i];
for(inti=la-lb;i>=0;--i){
while(greater_eq(d,b,i,lb)){
for(intj=0;jlb;++j){
d[i+j]-=b[j];
if(d[i+j]0){
d[i+j+1]-=1;
d[i+j]+=10;
}
}
c[i]+=1;
}
}
}

intmain(){
read(a);

charop[4];
scanf("%s",op);

read(b);

switch(op[0]){
case'+':
add(a,b,c);
print(c);
break;
case'-':
sub(a,b,c);
print(c);
break;
case'*':
mul(a,b,c);
print(c);
break;
case'/':
div(a,b,c,d);
print(c);
print(d);
break;
default:
puts(">);
}

return0;
}

Áp vị cao độ chặt chẽ

Dẫn vào

Ở giống nhau cao độ chặt chẽ toán cộng, phép trừ, phép nhân giải toán trung, chúng ta đều là đem tham dự giải toán số tách ra thành từng cái đơn độc chữ số tiến hành giải toán.

Tỷ như tính toánKhi, nếu dựa theo cao độ chặt chẽ thừa cao độ chặt chẽ tính toán phương thức, chúng ta trên thực tế tính chính là.

Tại vị số so nhiều thời điểm, tách ra ra số cũng rất nhiều, cao độ chặt chẽ giải toán hiệu suất liền sẽ giảm xuống.

Có biện pháp nào không làm ra một ít ưu hoá đâu?

Chú ý tới tách ra con số phương thức cũng không ảnh hưởng cuối cùng kết quả, bởi vậy chúng ta có thể đem bao nhiêu cái chữ số tiến hành xác nhập.

Quá trình

Vẫn là trở lên mặt cái này ví dụ vì lệ, nếu chúng ta mỗi hai vị tách ra một số, chúng ta có thể tách ra thành.

Như vậy tách ra không ảnh hưởng cuối cùng kết quả, nhưng là bởi vì tách ra ra con số biến thiếu, tính toán hiệu suất cũng liền tăng lên.

TừTiến vị chếGóc độ lý giải này một quá trình, chúng ta thông qua ở trọng đại tiến vị chế ( mặt trên mỗi hai vị tách ra một số, có thể cho rằng là ởTiến chế hạ tiến hành giải toán ) hạ tiến hành giải toán, do đó đạt tới giảm bớt tham dự giải toán con số vị số, tăng lên giải toán hiệu suất mục đích.

Đây làÁp vị cao độ chặt chẽTư tưởng.

Phía dưới chúng ta cấp ra áp vị cao độ chặt chẽ toán cộng số hiệu, dùng cho tiến thêm một bước trình bày kỳ thật hiện phương pháp:

Áp vị cao độ chặt chẽ toán cộng tham khảo thực hiện
1
2
3
4
5
6
7
8
9
10
11
12
13
// nơi này a,b,c số tổ đều vì p tiến chế hạ số
// cuối cùng phát ra đáp án khi yêu cầu đem con số chuyển vì số thập phân
voidadd(inta[],intb[],intc[]){
clear(c);

for(inti=0;iLEN-1;++i){
c[i]+=a[i]+b[i];
if(c[i]>=p){// ở bình thường cao độ chặt chẽ giải toán hạ, p=10
c[i+1]+=1;
c[i]-=p;
}
}
}

Áp vị cao tinh hạ hiệu suất cao dựng thức phép chia

Ở sử dụng áp vị cao tinh khi, nếu thí thương khi vẫn cứ sử dụng câu trên giới thiệu phương pháp, bởi vì thí thương số lần sẽ rất nhiều, tính toán hằng số sẽ phi thường đại. Tỷ như ở vạn tiến chế hạ, bình quân mỗi cái vị yêu cầu thí thương 5000 thứ, cái này thật lớn hằng số là không thể tiếp thu. Bởi vậy chúng ta yêu cầu một cái càng cao hiệu thí thương biện pháp.

Chúng ta có thể đem double làm môi giới. Giả thiết số bị chia có 4 vị, là,Số chia có 3 vị, là,Như vậy chúng ta chỉ cần thí một vị thương: Sử dụngTiến chế, dùng tư thếTới đánh giá thương. Mà đối với nhiều vị tình huống, chính là một vị phương pháp sáng tác thêm cái tuần hoàn. Bởi vì số chia sử dụng 3 vị độ chặt chẽ tới tham dự đánh giá thương, có thể bảo đảm đánh giá thương q' cùng thực tế thương q quan hệ thỏa mãn,Như vậy mỗi cái vị ở nhất hư dưới tình huống cũng chỉ yêu cầu hai lần thí thương. Nhưng cùng lúc đó yêu cầuỞ double hữu hiệu độ chặt chẽ nội, tức,Cho nên ở vận dụng phương pháp này khi kiến nghị không cần vượt qua 32768 tiến chế, nếu không thực dễ dàng nhân độ chặt chẽ không đủ sinh ra khác biệt do đó dẫn tới sai lầm.

Mặt khác, bởi vì đánh giá thương luôn là nhỏ hơn hoặc bằng thực tế thương, cho nên còn có lại tiến thêm một bước ưu hoá không gian. Tuyệt đại đa số dưới tình huống mỗi cái vị chỉ đánh giá thương một lần, như vậy tại hạ một cái vị đánh giá thương khi, tuy rằng được đến thương có khả năng bởi vì trước một vị khác biệt tạo thành thí thương kết quả lớn hơn hoặc bằng base, nhưng này không có quan hệ, chỉ cần ở cuối cùng làm thống nhất tiến vị liền có thể. Cử cái ví dụ, giả thiết base là 10, cầu,Thí thương lượng tính bước đi như sau:

  1. Đầu tiên thí thương lượng tính đến đến,Vì thế,Này một bước xuất hiện khác biệt, nhưng không cần phải xen vào, tiếp tục bước tiếp theo tính toán.
  2. Đối số dư 98801 tiếp tục thí thương lượng tính đến đến,Vì thế,Đây là cuối cùng số dư.
  3. Đem thí thương quá trình kết quả thêm lên cũng xử lý tiến vị, tứcĐó là chuẩn xác thương.

Phương pháp tuy rằng nhìn đơn giản, nhưng cụ thể thực hiện thượng thực dễ dàng tiến hố, cho nên dưới cung cấp một cái trải qua nhiều phiên nghiệm chứng xác nhận không có vấn đề thực hiện cung đại gia tham khảo, phải chú ý chi tiết cũng viết ở chú thích giữa.

Áp vị cao độ chặt chẽ hiệu suất cao dựng thức phép chia tham khảo thực hiện
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// hoàn chỉnh khuôn mẫu cùng thực hiện https://baobaobear.github.io/post/20210228-bigint1/
// đối b thừa lấy mul lại tả di offset kết quả tương giảm, vì phép chia phục vụ
BigIntSimple&sub_mul(constBigIntSimple&b,intmul,intoffset){
if(mul==0)return*this;
intborrow=0;
// cùng phép trừ bất đồng chính là, borrow khả năng rất lớn, không thể sử dụng phép trừ phương pháp sáng tác
for(size_ti=0;ib.v.size();++i){
borrow+=v[i+offset]-b.v[i]*mul-BIGINT_BASE+1;
v[i+offset]=borrow%BIGINT_BASE+BIGINT_BASE-1;
borrow/=BIGINT_BASE;
}
// nếu còn có tá vị liền tiếp tục xử lý
for(size_ti=b.v.size();borrow;++i){
borrow+=v[i+offset]-BIGINT_BASE+1;
v[i+offset]=borrow%BIGINT_BASE+BIGINT_BASE-1;
borrow/=BIGINT_BASE;
}
return*this;
}

BigIntSimplediv_mod(constBigIntSimple&b,BigIntSimple&r)const{
BigIntSimpled;
r=*this;
if(absless(b))returnd;
d.v.resize(v.size()-b.v.size()+1);
// trước tiên tính hảo số chia tối cao ba vị +1 đếm ngược, nếu tối cao ba vị là a3,a2,a1
// như vậy db là a3+a2/base+(a1+1)/base^2 đếm ngược, cuối cùng dùng phép nhân đánh giá thương mỗi một vị
// này pháp ở BIGINT_BASE
// nhưng cho dù sử dụng int64, như vậy cũng chỉ có BIGINT_BASE
// có thể bảo đảm phỏng chừng kết quả q' cùng thực tế kết quả q quan hệ thỏa mãn q'
// cho nên mỗi một vị thí thương bình quân chỉ cần một lần, chỉ cần mặt sau lại thống nhất xử lý tiến vị có thể
// nếu muốn sử dụng lớn hơn nữa base, như vậy yêu cầu đổi mới cái khác thí thương phương án
doublet=(b.get((unsigned)b.v.size()-2)+
(b.get((unsigned)b.v.size()-3)+1.0)/BIGINT_BASE);
doubledb=1.0/(b.v.back()+t/BIGINT_BASE);
for(size_ti=v.size()-1,j=d.v.size()-1;jv.size();){
intrm=r.get(i+1)*BIGINT_BASE+r.get(i);
intm=std::max((int)(db*rm),r.get(i+1));
r.sub_mul(b,m,j);
d.v[j]+=m;
if(!r.get(i+1))// kiểm tra tối cao vị hay không đã vì 0, tránh cho cực đoan tình huống
--i,--j;
}
r.trim();
// tu chỉnh kết quả hàng đơn vị
intcarry=0;
while(!r.absless(b)){
r.subtract(b);
++carry;
}
// tu chỉnh mỗi một vị tiến vị
for(size_ti=0;id.v.size();++i){
carry+=d.v[i];
d.v[i]=carry%BIGINT_BASE;
carry/=BIGINT_BASE;
}
d.trim();
d.sign=sign*b.sign;
returnd;
}

BigIntSimpleoperator/(constBigIntSimple&b)const{
BigIntSimpler;
returndiv_mod(b,r);
}

BigIntSimpleoperator%(constBigIntSimple&b)const{
BigIntSimpler;
div_mod(b,r);
returnr;
}

Karatsuba phép nhân

Nhớ cao độ chặt chẽ con số vị số vì,Như vậy cao độ chặt chẽ — cao độ chặt chẽ dựng thức phép nhân yêu cầu tiêu phíThời gian. Bổn tiết giới thiệu một cái thời gian phức tạp độ càng vì ưu tú thuật toán, từ trước Liên Xô ( Nga ) toán học gia Anatoly Karatsuba đưa ra, là một loại phân trị thuật toán.

Suy xét hai cái số thập phân đại số nguyênCùng,Đều bao hàmCái chữ số ( có thể có dẫn đường linh ). Nhậm lấy,Nhớ

Trong đó.Nhưng đến

Quan sát biết

Vì thế muốn tính toán,Chỉ cần tính toán,Lại cùng,Tương giảm là được.

Thượng thức trên thực tế là Karatsuba thuật toán trung tâm, nó đem chiều dài vìPhép nhân vấn đề chuyển hóa vìCái chiều dài càng tiểu nhân tử vấn đề. Nếu lệnh,Nhớ Karatsuba thuật toán tính toán hai cáiVị số nguyên phép nhân tốn thời gian vì,Tắc có,Từ chủ định lý nhưng đến.

Toàn bộ quá trình có thể đệ quy thực hiện. Vì rõ ràng khởi kiến, phía dưới số hiệu thông qua Karatsuba thuật toán thực hiện đa thức phép nhân, cuối cùng lại xử lý sở hữu tiến vị vấn đề.

karatsuba_mulc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
int*karatsuba_polymul(intn,int*a,int*b){
if(n32){
// quy mô nhỏ lại khi trực tiếp tính toán, tránh cho tiếp tục đệ quy mang đến hiệu suất tổn thất
int*r=newint[n*2+1]();
for(inti=0;in;++i)
for(intj=0;jn;++j)r[i+j]+=a[i]*b[j];
returnr;
}

intm=n/2+1;
int*r=newint[m*4+1]();
int*z0,*z1,*z2;

z0=karatsuba_polymul(m-1,a,b);
z2=karatsuba_polymul(n-m,a+m,b+m);

// tính toán z1
// lâm thời sửa đổi, tính toán xong sau khôi phục
for(inti=0;i+mn;++i)a[i]+=a[i+m];
for(inti=0;i+mn;++i)b[i]+=b[i+m];
z1=karatsuba_polymul(m-1,a,b);
for(inti=0;i+mn;++i)a[i]-=a[i+m];
for(inti=0;i+mn;++i)b[i]-=b[i+m];
for(inti=0;i(m-1)*2;++i)z1[i]-=z0[i];
for(inti=0;i(n-m)*2;++i)z1[i]-=z2[i];

// từ z0, z1, z2 tổ hợp đạt được kết quả
for(inti=0;i(m-1)*2;++i)r[i]+=z0[i];
for(inti=0;i(m-1)*2;++i)r[i+m]+=z1[i];
for(inti=0;i(n-m)*2;++i)r[i+m*2]+=z2[i];

delete[]z0;
delete[]z1;
delete[]z2;
returnr;
}

voidkaratsuba_mul(inta[],intb[],intc[]){
int*r=karatsuba_polymul(LEN-1,a,b);
memcpy(c,r,sizeof(int)*LEN);
for(inti=0;iLEN-1;++i)
if(c[i]>=10){
c[i+1]+=c[i]/10;
c[i]%=10;
}
delete[]r;
}
VềnewCùngdelete

ThấyNội tồn trì.

Nhưng là như vậy thực hiện tồn tại một vấn đề: ỞTiến chế hạ, đa thức mỗi một cái hệ số đều có khả năng đạt tớiLượng cấp, ở áp vị cao độ chặt chẽ thực hiện trung khả năng tạo thành số nguyên tràn ra; mà nếu ở đa thức phép nhân trong quá trình xử lý tiến vị vấn đề, tắcCùngKết quả khả năng đạt tới,Gia tăng một cái vị ( nếu chọn dùngTính toán phương thức, tắc không thể không đặc thù xử lý số âm tình huống ). Bởi vậy, yêu cầu y theo thực tế ứng dụng cảnh tượng tới quyết định chọn dùng loại nào thực hiện phương thức.

Căn cứ vào đa thức hiệu suất cao đại số nguyên phép nhân

Nếu số liệu quy mô đạt tớiHoặc lớn hơn nữa, bình thường cao độ chặt chẽ phép nhân khả năng sẽ siêu khi. Bổn tiết đem giới thiệu dùng đa thức ưu hoá này loại phép nhân phương pháp.

Đối với một cáiVị số thập phân số nguyên,Có thể đem nó coi như một cái mỗi vị hệ số đều vì số nguyên thả không vượt quaĐa thức.Như vậy, chúng ta liền đem hai cái số nguyên phép nhân chuyển hóa vì hai cái đa thức phép nhân.

Bình thường đa thức phép nhân thời gian phức tạp độ vẫn là,Nhưng có thể dùng đa thức một tiết trungNhanh chóng Fourier biến hóa,Nhanh chóng số luận biến hóaChờ thuật toán ưu hoá, ưu hoá sau thời gian phức tạp độ là.

Phong trang loại

Nơi nàyCó một cái phong trang tốt cao độ chặt chẽ số nguyên loại, cùng vớiNơi nàyDuy trì động thái chiều dài cập bốn phép tính giải toán siêu mini thực hiện loại.

Nơi này là một cái khác khuôn mẫu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#define MAXN 9999
// MAXN là một vị trung lớn nhất con số
#define MAXSIZE 10024
// MAXSIZE là vị số
#define DLEN 4

// DLEN ký lục áp vài vị
structBig{
inta[MAXSIZE],len;
boolflag;// đánh dấu ký hiệu '-'

Big(){
len=1;
memset(a,0,sizeofa);
flag=0;
}

Big(constint);
Big(constchar*);
Big(constBig&);
Big&operator=(constBig&);
Bigoperator+(constBig&)const;
Bigoperator-(constBig&)const;
Bigoperator*(constBig&)const;
Bigoperator/(constint&)const;
// TODO: Big / Big;
Bigoperator^(constint&)const;
// TODO: Big ^ Big;

// TODO: Big vị giải toán;

intoperator%(constint&)const;
// TODO: Big ^ Big;
booloperator(constBig&)const;
booloperator(constint&t)const;
voidprint()const;
};

Big::Big(constintb){
intc,d=b;
len=0;
// memset(a,0,sizeof a);
CLR(a);
while(d>MAXN){
c=d-(d/(MAXN+1)*(MAXN+1));
d=d/(MAXN+1);
a[len++]=c;
}
a[len++]=d;
}

Big::Big(constchar*s){
intt,k,index,l;
CLR(a);
l=strlen(s);
len=l/DLEN;
if(l%DLEN)++len;
index=0;
for(inti=l-1;i>=0;i-=DLEN){
t=0;
k=i-DLEN+1;
if(k0)k=0;
g(j,k,i)t=t*10+s[j]-'0';
a[index++]=t;
}
}

Big::Big(constBig&T):len(T.len){
CLR(a);
f(i,0,len)a[i]=T.a[i];
// TODO: Trọng tái nơi này?
}

Big&Big::operator=(constBig&T){
CLR(a);
len=T.len;
f(i,0,len)a[i]=T.a[i];
return*this;
}

BigBig::operator+(constBig&T)const{
Bigt(*this);
intbig=len;
if(T.len>len)big=T.len;
f(i,0,big){
t.a[i]+=T.a[i];
if(t.a[i]>MAXN){
++t.a[i+1];
t.a[i]-=MAXN+1;
}
}
if(t.a[big])
t.len=big+1;
else
t.len=big;
returnt;
}

BigBig::operator-(constBig&T)const{
intbig;
boolctf;
Bigt1,t2;
if(*thisT){
t1=T;
t2=*this;
ctf=1;
}else{
t1=*this;
t2=T;
ctf=0;
}
big=t1.len;
intj=0;
f(i,0,big){
if(t1.a[i]t2.a[i]){
j=i+1;
while(t1.a[j]==0)++j;
--t1.a[j--];
// WTF?
while(j>i)t1.a[j--]+=MAXN;
t1.a[i]+=MAXN+1-t2.a[i];
}else
t1.a[i]-=t2.a[i];
}
t1.len=big;
while(t1.len>1&&t1.a[t1.len-1]==0){
--t1.len;
--big;
}
if(ctf)t1.a[big-1]=-t1.a[big-1];
returnt1;
}

BigBig::operator*(constBig&T)const{
Bigres;
intup;
intte,tee;
f(i,0,len){
up=0;
f(j,0,T.len){
te=a[i]*T.a[j]+res.a[i+j]+up;
if(te>MAXN){
tee=te-te/(MAXN+1)*(MAXN+1);
up=te/(MAXN+1);
res.a[i+j]=tee;
}else{
up=0;
res.a[i+j]=te;
}
}
if(up)res.a[i+T.len]=up;
}
res.len=len+T.len;
while(res.len>1&&res.a[res.len-1]==0)--res.len;
returnres;
}

BigBig::operator/(constint&b)const{
Bigres;
intdown=0;
gd(i,len-1,0){
res.a[i]=(a[i]+down*(MAXN+1))/b;
down=a[i]+down*(MAXN+1)-res.a[i]*b;
}
res.len=len;
while(res.len>1&&res.a[res.len-1]==0)--res.len;
returnres;
}

intBig::operator%(constint&b)const{
intd=0;
gd(i,len-1,0)d=(d*(MAXN+1)%b+a[i])%b;
returnd;
}

BigBig::operator^(constint&n)const{
Bigt(n),res(1);
inty=n;
while(y){
if(y&1)res=res*t;
t=t*t;
y>>=1;
}
returnres;
}

boolBig::operator(constBig&T)const{
intln;
if(lenT.len)return233;
if(len==T.len){
ln=len-1;
while(ln>=0&&a[ln]==T.a[ln])--ln;
if(ln>=0&&a[ln]T.a[ln])return233;
return0;
}
return0;
}

boolBig::operator(constint&t)const{
Bigtee(t);
return*thistee;
}

voidBig::print()const{
printf("%d",a[len-1]);
gd(i,len-2,0){printf("%04d",a[i]);}
}

voidprint(constBig&s){
intlen=s.len;
printf("%d",s.a[len-1]);
gd(i,len-2,0){printf("%04d",s.a[i]);}
}

chars[100024];

Bài tập

Tham khảo tư liệu cùng liên tiếp

  1. Karatsuba algorithm - Wikipedia