1. 概念引入:乘法原理的模拟

高精度乘法用于计算两个超过内置数据类型(如 long long)存储范围的超大整数 A\text{A}B\text{B} 的乘积 A×B\text{A} \times \text{B}

其核心原理是模拟我们日常进行竖式乘法的过程

  1. 逐位相乘: 将乘数 B\text{B} 的每一位,依次乘以被乘数 A\text{A} 的每一位。
  2. 错位相加: 将所有这些乘积(即中间结果)根据其位数位置错位对齐后,进行累加。
  3. 统一进位: 最后,对累加得到的结果进行统一的进位处理。

2. 实现步骤与代码解析

我们将以您提供的代码为例,分步解析高精度乘法的实现。


步骤 A:输入与逆序存储

与高精度加法和减法相同,为了方便计算和处理位数,我们采用逆序存储的方式,将大整数的个位存入数组下标 1 的位置。

代码解析:

char a[200],b[200];
cin >> a >> b;
int lena = strlen(a); // A的长度
int lenb = strlen(b); // B的长度

// 将 A 逆序存入 a1,个位在 a1[1]
for(int i = 1; i <= lena; i++)
{
    a1[i] = a[lena-i]-'0';
}
// 将 B 逆序存入 b1,个位在 b1[1]
for(int i = 1; i <= lenb; i++)
{
    b1[i] = b[lenb-i]-'0';
}

步骤 B:核心运算——逐位相乘与累加

这一步是乘法的核心。我们使用双重循环来模拟 A\text{A} 的每一位乘以 B\text{B} 的每一位,并将乘积累加到结果数组 c\text{c} 中对应位置。

关键原理:位数对应关系

如果 AA 的第 ii 位(a1[i]\text{a1}[i],代表 10i110^{i-1})乘以 BB 的第 jj 位(b1[j]\text{b1}[j],代表 10j110^{j-1}),那么它们的乘积应该累加到结果的第 i+j1i+j-1 位上(代表 10i+j210^{i+j-2})。

运算 AA 的位次 BB 的位次 结果 CC 的位次 结果 CC 的数组下标
a1[i]×b1[j]\text{a1}[i] \times \text{b1}[j] ii jj i+j1i+j-1
示例:个位 ×\times 个位 i=1i=1 j=1j=1 11 (个位) 1+11=11+1-1=1
示例:十位 ×\times 个位 i=2i=2 22 (十位) 2+11=22+1-1=2

代码解析:

for(int i=1;i<=lena;i++) // 遍历 A 的每一位
{
    for(int j=1;j<=lenb;j++) // 遍历 B 的每一位
    {
        // 累加:将 a1[i] * b1[j] 的乘积累加到结果 c[i+j-1] 上
        // 此时 c[i+j-1] 存储的是可能大于 10 的中间和
        c[i+j-1] += a1[i] * b1[j];
    }
}

步骤 C:统一进位处理

经过步骤 B 后,结果数组 c\text{c} 中的每一位可能都大于 9(例如 9×9=819 \times 9 = 81 可能会被累加多次)。我们需要从低位向高位统一进行进位处理

结果的最大长度: 两个 NN 位数的乘积最多是 2N2N 位。在这里,最大长度是 lena+lenblena + lenb

代码解析:

int len = lena + lenb; // 结果的最大可能长度

for(int i = 1; i <= len; i++) // 遍历结果 c 的每一位
{
    // 将当前位 c[i] 产生的进位加到下一位 c[i+1] 上
    c[i+1] += c[i] / 10;
    
    // 当前位只保留个位数
    c[i] = c[i] % 10;
}

步骤 D:处理前导零与输出结果

代码解析:

lenc = len; // 从结果的最大长度开始判断

// 跳过最高位可能的无效 0 (例如 10 * 10 = 100, 结果数组长度是 4,但 c[4] = 0)
while(c[lenc] == 0 && lenc > 1)
{
    lenc--; // 缩短实际长度
}

// 逆序输出数组 c,得到最终结果
for(int i = lenc; i >= 1; i--)
{
    cout << c[i];
}

3. 完整代码(高精度乘法)

#include <bits/stdc++.h>
using namespace std;

int a1[200],b1[200],c[200]; // 用数组存储大整数

int main()
{
	char a[200],b[200];
	cin >> a >> b;
	int lena = strlen(a);
	int lenb = strlen(b);
	
	// --- 步骤 A: 逆序存储 ---
	for(int i=1;i<=lena;i++)
	{
		a1[i]=a[lena-i]-'0';
	}
	
	for(int i=1;i<=lenb;i++)
	{
		b1[i]=b[lenb-i]-'0';
	}
	
	// --- 步骤 B: 逐位相乘与累加 ---
	for(int i=1;i<=lena;i++)
	{
		for(int j=1;j<=lenb;j++)
		{
			// 乘积累加到对应的 c[i+j-1] 位置
			c[i+j-1] += a1[i] * b1[j];
		}
	}
	
	// --- 步骤 C: 统一进位处理 ---
	int len = lena + lenb; // 结果最大长度
	
	for(int i = 1; i <= len; i++)
	{
		// 进位加给下一位 c[i+1]
		c[i+1] += c[i] / 10;
		// 当前位只保留个位
		c[i] = c[i] % 10;
	}
	
	// --- 步骤 D: 处理前导零与输出 ---
	int lenc = len;
	
	// 找到实际的最高位
	while(c[lenc] == 0 && lenc > 1)
	{
		lenc--;
	}
	
	// 逆序输出结果
	for(int i=lenc;i>=1;i--)
	{
		cout << c[i];
	}
	cout << endl;
	
	return 0;
}

0 条评论

目前还没有评论...