高精度算法
1.高精度加法
// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
-
参数调整:首先,函数通过比较
A
和B
的大小,如果A
的位数少于B
,则递归调用add
函数并交换A
和B
的顺序,这样可以确保在后续的计算中,始终以位数较多的数作为遍历的基准,简化了代码的逻辑 -
初始化结果容器和进位标志:定义一个空的
vector<int>
类型的变量C
,用于存储相加的结果。同时,初始化一个整数变量t
为 0,用于表示进位 -
遍历相加:使用
for
循环遍历A
的每一位数字。在每次循环中,先将A
当前位的数字加到进位t
上,然后判断如果i
小于B
的大小,说明B
在当前位还有数字,则将B
当前位的数字也加到t
上。接着,将t
除以 10 的余数作为当前位的结果插入到结果容器C
中,并更新进位t
的值,即t
除以 10 取整,为下一位的加法运算做准备 -
处理最后进位:循环结束后,如果进位
t
的值不为 0,说明最高位还有进位,则将进位t
作为新的最高位插入到结果容器C
中 -
返回结果:最后,函数返回存储结果的
vector<int>
类型的变量C
,即为两个大整数相加的最终结果
2.高精度减法
// C = A - B, 满足A >= B, A >= 0, B >= 0
vector<int> sub(vector<int> &A, vector<int> &B)
{
vector<int> C;
for (int i = 0, t = 0; i < A.size(); i ++ )
{
t = A[i] - t;
if (i < B.size()) t -= B[i];
C.push_back((t + 10) % 10);
if (t < 0) t = 1;
else t = 0;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
定义结果向量 C
用于存储差值的每一位数字,同时初始化循环变量 i
和临时变量 t
,t
用于暂存减法过程中的借位信息及每一步的计算结果。
在循环中,先从 A
的当前位数字减去上一步的借位值 t
,若 B
还有对应位数字(i < B.size()
),则再减去 B
的当前位数字。将计算结果对 10
取模后存入 C
,以得到当前位的差。若计算结果小于 0
,说明需要借位,将 t
设为 1
表示借位;否则将 t
设为 0
,表示无借位。
计算完成后,由于结果可能存在前导 0
(例如 123 - 120 = 003
),通过循环删除 C
末尾连续的 0
,只保留有效数字部分,但至少保留一位数字,以处理如 10 - 5 = 5
的情况,防止误删。
假设 A = {1, 2, 3}
,B = {1, 2, 0}
,计算 A - B
过程如下:
第一轮循环:i = 0
,t = 0
,t = A[0] - t = 1 - 0 = 1
,B
在此位有数字,t -= B[0] = 1 - 1 = 0
,C.push_back((t + 10) % 10) = 0
,t = 0
。
第二轮循环:i = 1
,t = 0
,t = A[1] - t = 2 - 0 = 2
,t -= B[1] = 2 - 2 = 0
,C.push_back((t + 10) % 10) = 0
,t = 0
。
第三轮循环:i = 2
,t = 0
,t = A[2] - t = 3 - 0 = 3
,B
在此位无数字,C.push_back((t + 10) % 10) = 3
,t = 0
。 最终 C = {0, 0, 3}
,去除前导 0
后为 {3}
,即 A - B = 3
。
3.高精度乘低精度
// C = A * b, A >= 0, b >= 0
vector<int> mul(vector<int> &A, int b)
{
vector<int> C;
int t = 0;
for (int i = 0; i < A.size() || t; i ++ )
{
if (i < A.size()) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
这段代码定义了一个名为 mul
的函数,用于实现高精度整数乘法运算。函数接收一个表示高精度整数的 vector<int>
类型的参数 A
(其中每个元素按低位到高位的顺序存储整数的每一位数字)以及一个普通的非负整数 b
,计算 A
与 b
的乘积,并返回表示乘积结果的 vector<int>
,同样按低位到高位存储每一位数字,同时对结果末尾可能存在的多余 0
进行了去除处理。
首先定义了一个名为 mul
的函数,它接受一个 vector<int>
类型的引用 A
(使用引用可以避免在函数调用时进行整个 vector
的拷贝,提高效率,尤其是对于较大的 vector
时)和一个 int
类型的整数 b
,函数的返回值类型为 vector<int>
,即返回表示乘法运算结果的整数数组(按位存储)。
在函数内部,定义了一个新的 vector<int>
类型的变量 C
,用于存储最终的乘法运算结果,初始为空。还定义了一个整型变量 t
,用于暂存每一步运算产生的进位,初始化为 0
。
这里使用了一个 for
循环来模拟竖式乘法的过程,循环条件 i < A.size() || t
表示只要还没遍历完 A
向量中的所有元素或者还有进位(t
不为 0
),就继续循环。
在循环体中,首先判断如果当前索引 i
小于 A
的大小,就将 A
中当前位数字与 b
相乘,并累加到 t
上(模拟乘法运算的每一位相乘以及进位累加过程)。
然后将 t
的个位数(即 t % 10
)通过 push_back
函数添加到结果向量 C
中,这相当于获取当前位的结果数字并存储到结果中。
最后将 t
除以 10
,去掉已经处理过的个位数,得到新的进位值,用于下一次循环的进位处理。
这是一个 while
循环,用于去除结果向量 C
末尾可能存在的多余的 0
。
条件 C.size() > 1 && C.back() == 0
表示当结果向量长度大于 1
(避免把唯一的一位数字 0
也去掉了)并且最后一位数字是 0
时,就调用 pop_back
函数删除最后一位数字,直到不满足这个条件为止,也就是把末尾连续的 0
都去掉了。
最后函数返回处理好的结果向量 C
,也就是 A
和 b
的高精度乘法运算的最终结果。
4.高精度除法
// A / b = C ... r, A >= 0, b > 0
vector<int> div(vector<int> &A, int b, int &r)
{
vector<int> C;
r = 0;
for (int i = A.size() - 1; i >= 0; i -- )
{
r = r * 10 + A[i];
C.push_back(r / b);
r %= b;
}
reverse(C.begin(), C.end());
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
该代码实现了高精度整数除法的功能。给定一个表示高精度整数的 vector<int>
类型的被除数 A
(按低位到高位的顺序存储每一位数字)、一个正整数除数 b
,通过函数运算得到商 C
(同样以 vector<int>
按低位到高位存储每一位数字)以及余数 r
,并且对商的结果做了去除末尾多余 0
的处理。
定义了名为 div
的函数,它接收三个参数:一个 vector<int>
类型的引用 A
(引用传递可避免大对象拷贝,提高效率)作为被除数,一个 int
类型的正整数 b
作为除数,一个 int
类型的引用 r
用于存储余数。函数的返回值类型是 vector<int>
,代表商。
在函数内部,首先创建了一个空的 vector<int>
变量 C
,用于后续存储计算得到的商。然后将余数 r
初始化为 0
,为后续的除法运算做准备
这里使用一个从高位到低位遍历被除数 A
的 for
循环来模拟手工进行除法运算的过程。
在每次循环中,先将当前余数 r
乘以 10
(相当于将余数左移一位,为加上被除数的下一位数字做准备,模拟竖式除法中逐位除的操作),再加上被除数 A
当前位的数字,得到新的临时数值(也就是当前这一步除法运算的被除数部分)。
接着将这个新的临时数值除以除数 b
,得到的商通过 push_back
函数添加到结果向量 C
中,这就完成了商的当前位数字的计算。
最后,通过 r %= b
计算得到这一步运算后的余数,用于下一次循环与被除数的下一位数字继续进行除法运算。
由于之前是从高位到低位依次计算并存储商的每一位数字到 C
中,所以需要调用 reverse
函数将 C
的元素顺序反转过来,使其符合正常的数字表示顺序(从低位到高位)。
然后使用 while
循环来去除商 C
末尾可能存在的多余的 0
。条件 C.size() > 1 && C.back() == 0
表示当 C
的长度大于 1
(避免把唯一的一位数字 0
也去掉了)且最后一位数字是 0
时,就调用 pop_back
函数删除最后一位数字,直到不满足该条件为止,以此保证商的结果在表示上更加简洁合理。
最后函数返回处理好的结果向量 C
,也就是高精度整数除法运算得到的商。而余数则通过引用参数 r
传递回调用函数的地方,方便调用者获取余数信息。