高精四则(整数)
文章目录
注:高精整数运算,这一篇就够了
一、高精加法——倒序相加
1.1、高精加高精
1.1.1思路方法:
倒序,将末端的个位数经依次完全调序后,即为首位,自此,从左向右为低位到高位,依次相加并处理进位即可。
核心:低位相加向高位,记得处理1进位:。 因为两个各位数相加不会超过20,所以最多进位为1
// 这部分是伪代码,不能跑!不能跑!! vector<int> C(size, 0);//初始化,size大小未知 k = 0 // k为进位值,有进位为1,否则为0 // 外层循环处理,至结束 { C[i] = A[i] + B[i] + k;//A、B为处理后的、倒序的加数 k = C[i] / 10; C[i] %= 10; // C[i]存答案的第i位 }
有两种方法,一种是静态的、顺序数组存储方式,另一种为动态的、大小可变的vector数组,两者在细节上略有不同。
对于vector整型数组A而言,假如A中有n个数据,那么只能访问A[0]和A[n-1],对于下一个或者更靠后的位置比如A[n],是不能对其直接操作的,可以理解为动态数组目前开到了A[n-1],对于下一个数据下还没分配内存,这样直接赋值:A[n] = 5
,这不行!想要增加一个值为5的元素,这样写即可:A.push_back(5)
。这里完成了vector数组的初始化:vector C(size, 0);,使得即便没有C.push_back(value)
size次,也可以访问C[0]~C[size-1]之间的元素。
1.1.2具体实现
-
“静态数组”:大小不可改变,支持的位数由数组大小决定。
#include <iostream> #include <cstring> using namespace std; const int MAXLEN = 2010;//最多为2010位的大数 char t[MAXLEN]; char a[MAXLEN], b[MAXLEN]; int main() { cin >> t;//输入第一个数,并倒序 for (int i = strlen(t)-1, j = 0; i >= 0; -- i) a[j ++] = t[i] - '0'; cin >> t;//输入第二个数,并倒序 for (int i = strlen(t)-1, j = 0; i >= 0; -- i) b[j ++] = t[i] - '0'; for (int i = 0, k = 0; i < MAXLEN; ++ i) { a[i] += b[i] + k; k = a[i] / 10; a[i] %= 10; } //准备输出 int i = MAXLEN - 1; while (i >= 0 && !a[i]) -- i;//出去前导零 //如果存在输入数字0加0,则需要特判除去前导零后,是否有数,但一般不会出现这种情况 while (i >= 0) cout << (int)a[i --];//依次输出高位到低位 return 0; }
-
vector数组:大小可变、灵活,基本无限制(内存够用的前提下)。
#include <iostream> #include <string> #include <vector> using namespace std; //这样typedef后下面的VI可替换为vector<int> typedef vector<int> VI; VI Add(VI& A, VI& B) { VI C;// 存答案 int i = 0, k = 0; //先处理A和B的等长部分 while (i < A.size() && i < B.size()) { k += A[i] + B[i]; C.push_back(k % 10); k /= 10; ++ i; } //如果B每一位都加完了,A还有剩余,则将A剩余部分加到C中 while (i < A.size()) { k += A[i]; C.push_back(k % 10); k /= 10; ++ i; } //如果A每一位都加完了,B还有剩余,则将B剩余部分加到C中 while (i < B.size()) { k += B[i]; C.push_back(k % 10); k /= 10; ++ i; } return C; } int main() { string a, b; VI A, B, C;//A和B为存待操作数,C为结果 cin >> a >> b; for (int i = a.size()-1; i >= 0; -- i) A.push_back(a[i]-'0'); for (int i = b.size()-1; i >= 0; -- i) B.push_back(b[i]-'0'); C = Add(A, B); for (int i = C.size()- 1; i >= 0; -- i) cout << C[i]; return 0; }
1.2、高精加低精
1.2.1思路方法
与高精+高精类似,就是把其中一个改为低精度,对于低精度,同样的,为了每次获取其位置上的数,只需要每次对低精数处理即可。
核心:处理低精数
// 外层循环...两个条件 //1.A数组加完了 2.b加完了 { k += A[i] + b % 10; C.oush_back(k % 10); k /= 10, b /= 10; }
后续针对1,2两种情况处理,
如果A数组加完了,判断b是否为0,如果不为0,需要把b的每一位放入答案数组C中,即:
while (b) { C.push_back(b % 10); b /= 10; }
如果b加完了,判断A有没有加完,如果A有剩余,将A剩余每一位加入答案数组C中,即:
while (i < A.size()) { k += A[i]; C.push_back(k % 10); k /= 10; ++ i; }
1.2.2具体实现
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> VI;
VI Add(VI& A, int b)
{
VI C;//因为后面用的是push_back()的方式,没有初始化
int i = 0, k = 0;
while (i < A.size() && b != 0)
{
k += A[i] + b % 10;
C.push_back(k % 10);
k /= 10, b /= 10; ++ i;
}
while (i < A.size())
{
k += A[i];
C.push_back(k % 10);
k /= 10; ++ i;
}
while (b != 0)
{
k += b % 10;
C.push_back(k % 10);
k /= 10, b /= 10; ++ i;
}
return C;
}
int main()
{
VI A, C;
string a; int b;
cin >> a >> b;
for (int i = a.size()-1; i >= 0; -- i) A.push_back(a[i] - '0');
C = Add(A, b);
for (int i = C.size()-1; i >= 0; -- i) cout << C[i];
return 0;
}
二、高精减法——大小判断+倒序相减
2.1思路方法
先判断大小,始终用大减小的方式来计算。对于A - B,
A
−
B
=
{
A
−
B
;
A
≥
B
−
(
B
−
A
)
;
A
<
B
A - B = \left\{ \begin{aligned} & A - B; \ A \ {\geq} \ B \\ & - (B - A); \ A < B \end{aligned} \right.
A−B={A−B; A ≥ B−(B−A); A<B
核心:大减小,不够则借位,下一位需要减去这个借位
规则:低位借一算十,即低位加十,相邻高位减一
注意对前导0的处理,前导的出现是由于两数最高位数字大小相同造成的,如果最高位减为0则不应该输出,除去前导零:
while (C.size() > 1 && C.back() == 0) C.pop_back();
2.2具体实现
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> VI;
bool compare(VI& A, VI& B)
{
if (A.size() != B.size()) return A.size() > B.size();
for (int i = A.size()-1; i >= 0; -- i)
if (A[i] != B[i]) return A[i] > B[i];
return true;
}
VI sub(VI& A, VI& B)
{
VI C(A.size(), 0);
int i = 0, k = 1;
while (i < B.size())
{
C[i] = A[i] - B[i] - !k;
k = (C[i] + 10) / 10;
C[i] = (C[i] + 10) % 10;
++ i;
}
while (i < A.size())
{
C[i] = A[i] - !k;
k = (C[i] + 10) / 10;
C[i] = (C[i] + 10) % 10;
++ i;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
VI A, B, C;
string a, b;
cin >> a >> b;
for (int i = a.size()-1; i >= 0; -- i) A.push_back(a[i]-'0');
for (int i = b.size()-1; i >= 0; -- i) B.push_back(b[i]-'0');
if (compare(A, B)) C = sub(A, B);
else
{
cout << '-';
C = sub(B, A);
}
for (int i = C.size()-1; i >= 0; -- i) cout << C[i];
return 0;
}
三、高精乘法——倒序相乘+等级处理
3.1、高精乘高精
3.1.1思路方法:
将两个数倒序,呈由低位到高位排列。
核心:等级处理
个位 * 个位 = 个位
个位 * 十位 = 十位
十位 * 个位 = 十位
…
A数组从低位到高位A[0]~A[n]
B数组从低位到高位B[0]~B[m]
对于A数组的第i位,乘以B数组的第j位,得到答案数组C的第i+j位
(如果感觉不对,请注意下标从0开始存储的)
3.1.2具体实现
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> VI;
VI mul(VI& A, VI& B)
{
VI C(A.size()+B.size(), 0);
for (int i = 0; i < A.size(); ++ i)
for (int j = 0; j < B.size(); ++ j)
C[i+j] += A[i] * B[j];
int k = 0;
for (int i = 0; i < C.size(); ++ i)
{
C[i] += k;
k = C[i] / 10;
C[i] %= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
VI A, B, C;
string a, b;
cin >> a >> b;
for (int i = a.size()-1; i >= 0; -- i) A.push_back(a[i]-'0');
for (int i = b.size()-1; i >= 0; -- i) B.push_back(b[i]-'0');
C = mul(A, B);
for (int i = C.size()-1; i >= 0; -- i) cout << C[i];
return 0;
}
3.2、高精乘低精
3.2.1思路方法
与上面高精乘高精大致相同,但是细节不同。
核心:等级处理
大数倒序存于A数组中,A[0]~A[n-1]分别代表个位、十位、百位… 将A[0] ~ A[n-1]每个数乘以低精乘数b,代表有b个个位数、b个十位数、b个百位数…将结果存于答案数组C中,后续处理C。
证明这一做法的科学性: abcd,这个四位数,乘以G,假设结果为ans,那么ans = abcd * G。且abcd = a + 10b+100c+1000d,ans = a * G + 10b * G + 100c * G + 1000 * G,相当于每一位数乘以G,并且其等级不变,即:a (个位)* G + b(十位)*G + c(百位) *G + d千位() *G
3.2.2具体实现
#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> VI;
VI mul(VI& A, int b)
{
VI C(A.size(), 0);
int k = 0;
for (int i = 0; i < A.size(); ++ i)
{
C[i] = A[i] * b + k;
k = C[i] / 10;
C[i] %= 10;
}
while (k)
{
C.push_back(k % 10);
k /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
VI A, C;
string a; int b;
cin >> a >> b;
for (int i = a.size()-1; i >= 0; -- i) A.push_back(a[i]-'0');
C = mul(A, b);
for (int i = C.size()-1; i >= 0; -- i) cout << C[i];
return 0;
}
四、高精除法——模拟除法式
4.1思路方法
按照除法算式的思路,从高位到低位算,恰好不需要倒序。
核心:模拟除法式
(高位数 + 10*余数) / 除数 = 商(该位置答案值) …余数(下一位用)
最后剩下的的余数即为这个总式的余数
4.2具体实现
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef vector<int> VI;
VI div(VI& A, int b, int& r)
{
VI C(A.size(), 0);
for (int i = 0; i < A.size(); ++ i)
{
r = A[i] + r * 10;
C[i] = r / b;
r %= b;
}
reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
int main()
{
VI A, C;
string a; int b, r = 0;//r最后为余数
cin >> a >> b;
for (int i = 0; i < a.size(); ++ i) A.push_back(a[i]-'0');
C = div(A, b, r);
for (int i = C.size()-1; i >= 0; -- i) cout << C[i];
return 0;
}
THEEND…