📅  最后修改于: 2023-12-03 15:37:19.190000             🧑  作者: Mango
在 C++ 中,当需要将两个非常大的数字相乘时,可能会导致溢出或精度丢失的问题。因此,需要使用高精度计算来解决这个问题。
同时,当结果较大时,需要取模运算以避免超出数据类型的范围。本文将介绍如何在 C++ 中实现高精度计算和取模运算。
高精度计算的主要思路是将每一位上的数字分别存储,然后通过模拟手算的过程进行计算。
以下是实现高精度计算的基本框架:
const int MAXN = 10005; // 最大位数
struct BigNumber {
int num[MAXN]; // 数字数组
int len; // 数字长度
BigNumber() { // 构造函数
memset(num, 0, sizeof(num));
len = 1;
}
BigNumber(int x) { // 构造函数
memset(num, 0, sizeof(num));
len = 0;
while (x) {
num[len++] = x % 10;
x /= 10;
}
if (len == 0) len = 1;
}
void print() { // 输出函数
for (int i = len - 1; i >= 0; i--)
printf("%d", num[i]);
}
};
其中,num
数组用于存储每一位上的数字,len
表示数字的长度。构造函数用于将一个普通的整数转换为高精度数字。输出函数用于将高精度数字转换为普通的整数进行输出。
以下是实现高精度数字的加减乘除的代码示例:
// 高精度加法
BigNumber operator+(const BigNumber& A, const BigNumber& B) {
BigNumber C;
C.len = 0;
for (int i = 0, g = 0; g || i < max(A.len, B.len); i++) {
int x = g;
if (i < A.len) x += A.num[i];
if (i < B.len) x += B.num[i];
C.num[C.len++] = x % 10;
g = x / 10;
}
return C;
}
// 高精度减法
BigNumber operator-(const BigNumber& A, const BigNumber& B) {
BigNumber C;
C.len = 0;
for (int i = 0, g = 0; i < A.len; i++) {
int x = A.num[i] - g;
if (i < B.len) x -= B.num[i];
if (x >= 0) {
g = 0;
} else {
g = 1;
x += 10;
}
C.num[C.len++] = x;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C;
}
// 高精度乘法
BigNumber operator*(const BigNumber& A, const int& b) {
BigNumber C;
C.len = 0;
int t = 0;
for (int i = 0; i < A.len || t; i++) {
int x = t;
if (i < A.len) x += A.num[i] * b;
C.num[C.len++] = x % 10;
t = x / 10;
}
return C;
}
// 高精度除法
BigNumber operator/(const BigNumber& A, const int& b) {
BigNumber C;
C.len = A.len;
int r = 0;
for (int i = A.len - 1; i >= 0; i--) {
r = r * 10 + A.num[i];
C.num[i] = r / b;
r %= b;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C;
}
当两个数字的乘积较大时,为了避免超出数据类型的范围,需要使用取模运算将结果缩小。以下是常见的取模方法:
将每一步的结果都进行取模操作,最后再对整个结果进行一次取模运算。
const int MOD = 998244353;
// 高精度乘法取模
BigNumber operator*(const BigNumber& A, const BigNumber& B) {
BigNumber C;
C.len = A.len + B.len;
for (int i = 0; i < A.len; i++) {
int t = 0;
for (int j = 0; j < B.len; j++) {
t += A.num[i] * B.num[j] + C.num[i + j];
C.num[i + j] = t % 10;
t /= 10;
}
C.num[i + B.len] += t;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C % MOD;
}
将模数拆分成多个质数的乘积,分别对每个质数进行取模计算,最后再将结果合并。
// 高精度乘法取模(模数分解法)
const int P[] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
const int M = sizeof(P) / sizeof(int);
BigNumber mod(const BigNumber& A, const int& p) {
BigNumber C;
C.len = 0;
int r = 0;
for (int i = A.len - 1; i >= 0; i--) {
r = r * 10 + A.num[i];
C.num[i] = r / p;
r %= p;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C;
}
BigNumber operator%(const BigNumber& A, const int& m) {
BigNumber ans;
for (int i = 0; i < M; i++) {
if (m % P[i] == 0) {
ans = (ans + mod(A, P[i])) % m;
}
}
return ans;
}
BigNumber operator*(const BigNumber& A, const BigNumber& B, const int& M) {
BigNumber C;
C.len = A.len + B.len;
for (int i = 0; i < A.len; i++) {
int t = 0;
for (int j = 0; j < B.len; j++) {
t += A.num[i] * B.num[j] + C.num[i + j];
C.num[i + j] = t % 10;
t /= 10;
}
C.num[i + B.len] += t;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C % M;
}
以下是将两个数字相乘并取模的示例代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
struct BigNumber {
int num[MAXN];
int len;
BigNumber() {
memset(num, 0, sizeof(num));
len = 1;
}
BigNumber(int x) {
memset(num, 0, sizeof(num));
len = 0;
while (x) {
num[len++] = x % 10;
x /= 10;
}
if (len == 0) len = 1;
}
void print() {
for (int i = len - 1; i >= 0; i--)
printf("%d", num[i]);
}
};
BigNumber operator+(const BigNumber& A, const BigNumber& B) {
BigNumber C;
C.len = 0;
for (int i = 0, g = 0; g || i < max(A.len, B.len); i++) {
int x = g;
if (i < A.len) x += A.num[i];
if (i < B.len) x += B.num[i];
C.num[C.len++] = x % 10;
g = x / 10;
}
return C;
}
BigNumber operator-(const BigNumber& A, const BigNumber& B) {
BigNumber C;
C.len = 0;
for (int i = 0, g = 0; i < A.len; i++) {
int x = A.num[i] - g;
if (i < B.len) x -= B.num[i];
if (x >= 0) {
g = 0;
} else {
g = 1;
x += 10;
}
C.num[C.len++] = x;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C;
}
BigNumber operator*(const BigNumber& A, const int& b) {
BigNumber C;
C.len = 0;
int t = 0;
for (int i = 0; i < A.len || t; i++) {
int x = t;
if (i < A.len) x += A.num[i] * b;
C.num[C.len++] = x % 10;
t = x / 10;
}
return C;
}
BigNumber operator/(const BigNumber& A, const int& b) {
BigNumber C;
C.len = A.len;
int r = 0;
for (int i = A.len - 1; i >= 0; i--) {
r = r * 10 + A.num[i];
C.num[i] = r / b;
r %= b;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C;
}
const int MOD = 998244353;
BigNumber operator%(const BigNumber& A, const int& m) {
BigNumber ans;
for (int i = 2; i <= sqrt(m); i++) {
int p = 1;
while (m % i == 0) {
m /= i;
p *= i;
}
if (p > 1) ans = ans + (A % p) * (MOD / p) % MOD;
}
if (m > 1) ans = ans + A % m * (MOD / m) % MOD;
return ans % MOD;
}
BigNumber operator*(const BigNumber& A, const BigNumber& B) {
BigNumber C;
C.len = A.len + B.len;
for (int i = 0; i < A.len; i++) {
int t = 0;
for (int j = 0; j < B.len; j++) {
t += A.num[i] * B.num[j] + C.num[i + j];
C.num[i + j] = t % 10;
t /= 10;
}
C.num[i + B.len] += t;
}
while (C.len > 1 && C.num[C.len - 1] == 0)
C.len--;
return C % MOD;
}
int main() {
int a, b;
cin >> a >> b;
BigNumber A(a), B(b);
(A * B).print();
return 0;
}
本文介绍了如何在 C++ 中实现高精度计算和取模运算。使用高精度计算和取模运算可以解决两个非常大的数字相乘的问题,并且保证了精度和速度的性能。