高精度算法
问题引入
给你两个十进制运算数a, b,它们的长度不超过1000。你需要求解 a (op) b 的值(op 为 +, -, *, / 运算中的一种)。
注 :C++中long long 能表示的最大十进制数为"9223372036854775807"
数据存储
显然longlong也无法存储这个两个运算数了。在平常的实现中,高精度数字利用字符串表示,每一个字符表示数字的一个十进制位。因此可以说,高精度数值计算实际上是一种特别的字符串处理。
在读入字符串时,最高位在字符串首,但是习惯上,我们将最低位置于字符串首即翻转存储字符串。我们这么做的原因是将数位对齐。下面是一个例子: 1234 和 100
4 | 3 | 2 | 1 |
---|---|---|---|
0 | 0 | 1 | 0 |
我们规定:各位在下标0,十位在下标1 …逆序存储。可以写出下面的存储程序
void input(string a, string b){
clear();
la = a.length(), lb = b.length();
for(int i = la - 1; i >= 0; i--) A[la - i - 1] = a[i] - '0';
for(int i = lb - 1; i >= 0; i--) B[lb - i - 1] = b[i] - '0';
}
加法
我们模拟竖式加法。
从低位开始处理,若当前位C[i] >= 10, 后一位 C[i + 1] += 1, C[i] %= 10。
void add(){
int lc = max(la, lb);
for(int i = 0; i < la; i++){
C[i] += A[i] + B[i];
C[i + 1] += C[i]/10;
C[i] = C[i] % 10;
}
erase_pre0(C, lc); //去除前导0
Print(C, lc); //输出答案
}
减法:
类似于加法的实现,模拟竖式减法。需要处理一个细节,若 A >= B,我们可以直接模拟。 若 A < B 我们可以先交换A, B 最后先输出负号,再输出结果即可。需要先实现一个比较大小的函数。
void sub(){
if(!(greater_eq(A, B, 0, lb))) {
cout <<"-";
swap(A, B);
}
int lc = max(la, lb);
for(int i = 0; i < la; i++){
C[i] += A[i] - B[i];
if(C[i] < 0){
C[i + 1] -= 1;
C[i] += 10;
}
}
erase_pre0(C, lc);
Print(C, lc);
}
乘法
A i A_i Ai 表示A的第i位, B j B_j Bj表示B的第j位。 A i A_i Ai = a × \times × 1 0 i 10^i 10i, B j B_j Bj = b × \times × 1 0 j 10^j 10j。 A i A_i Ai × \times × B j B_j Bj = a × \times × b × \times × 1 0 i + j 10^{i + j} 10i+j。我们按序处理每一位。
void mul(){
int lc = la + lb;
for(int i = 0; i < la; i++){
for(int j = 0; j < lb; j++){
C[i + j] += A[i]*B[j];
C[i + j + 1] += C[i + j]/10;
C[i + j] = C[i + j]%10;
}
}
erase_pre0(C, lc);
Print(C, lc);
}
除法(高精度除高精度)
终于要完成了!!!
在高精度除法中,我们使用减法来模拟除法的过程,例如45 / 12,我们可以这么看45 - 12 - 12 - 12 = 9,即45/12 = 3 余 9。我们用高精度除法来模拟竖式长除。在这过程中有一个细节,我们需要比较被除数和除数的大小,可以借助上面减法程序中的比较函数。
void div(){
int lc = max(la, lb);
int ld = lc;
for(int i = 0; i < la; i++) D[i] = A[i];
for(int i = la - lb; i >= 0; i--){
while(greater_eq(D, B, i, lb)){
for(int j = 0; j < lb; j++){
D[i + j] -= B[j];
if(D[i + j] < 0){
D[i + j + 1] -= 1;
D[i + j] += 10;
}
}
C[i] += 1;
}
}
erase_pre0(C, lc);
erase_pre0(D, ld);
Print(C, lc);
Print(D, ld);
}
基本高精度算法!完成!
自己写的高精度计算器类
class calculator{
private:
public:
int A[N], B[N], C[N], D[N];
int la, lb;
void clear(){
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
memset(C, 0, sizeof(C));
memset(D, 0, sizeof(D));
}
calculator(){
clear();
}
void input(string a, string b){
clear();
la = a.length(), lb = b.length();
for(int i = la - 1; i >= 0; i--) A[la - i - 1] = a[i] - '0';
for(int i = lb - 1; i >= 0; i--) B[lb - i - 1] = b[i] - '0';
}
calculator(string a, string b){
la = a.length(), lb = b.length();
for(int i = la - 1; i >= 0; i--) A[la - i - 1] = a[i] - '0';
for(int i = lb - 1; i >= 0; i--) B[lb - i - 1] = b[i] - '0';
}
void Print(int a[], int pos){
for(int i = pos; i >= 0; i--) cout << a[i];
cout << endl;
}
bool greater_eq(int a[], int b[], int last_dg, int len){
if(a[last_dg + len] != 0) return 1;
for(int i = len - 1; i >= 0; i--){
if(a[last_dg + i] > b[i]) return 1;
if(a[last_dg + i] < b[i]) return 0;
}
return 1;
}
void erase_pre0(int a[], int& len){
while(len && a[len] == 0) len--;
}
void add(){
int lc = max(la, lb);
for(int i = 0; i < la; i++){
C[i] += A[i] + B[i];
C[i + 1] += C[i]/10;
C[i] = C[i] % 10;
}
erase_pre0(C, lc);
Print(C, lc);
}
void sub(){
if(!(greater_eq(A, B, 0, lb))) {
cout <<"-";
swap(A, B);
}
int lc = max(la, lb);
for(int i = 0; i < la; i++){
C[i] += A[i] - B[i];
if(C[i] < 0){
C[i + 1] -= 1;
C[i] += 10;
}
}
erase_pre0(C, lc);
Print(C, lc);
}
void mul(){
int lc = la + lb;
for(int i = 0; i < la; i++){
for(int j = 0; j < lb; j++){
C[i + j] += A[i]*B[j];
C[i + j + 1] += C[i + j]/10;
C[i + j] = C[i + j]%10;
}
}
erase_pre0(C, lc);
Print(C, lc);
}
void div(){
int lc = max(la, lb);
int ld = lc;
for(int i = 0; i < la; i++) D[i] = A[i];
for(int i = la - lb; i >= 0; i--){
while(greater_eq(D, B, i, lb)){
for(int j = 0; j < lb; j++){
D[i + j] -= B[j];
if(D[i + j] < 0){
D[i + j + 1] -= 1;
D[i + j] += 10;
}
}
C[i] += 1;
}
}
erase_pre0(C, lc);
erase_pre0(D, ld);
Print(C, lc);
Print(D, ld);
}
};