D a t e : 2022 − 10 − 07 \color{33CCFF}{Date:2022-10-07} Date:2022−10−07
L a s t \color{33CCFF}{Last} Last n i g h t \color{33CCFF}{night} night a \color{33CCFF}{a} a f e w \color{33CCFF}{few} few e x t r a \color{33CCFF}{extra} extra m i n u t e s \color{33CCFF}{minutes} minutes p r e p a r a t i o n , \color{33CCFF}{preparation,} preparation, f e w e r \color{33CCFF}{fewer} fewer h o u r s \color{33CCFF}{hours} hours o f \color{33CCFF}{of} of t r o u b l e \color{33CCFF}{trouble} trouble t o d a y ! \color{33CCFF}{today!} today!
对于32位字长的机器,大约超过20亿,用int类型无法表示,我们可以选择int64类型,但无论怎么扩展,固定的整数类型总有表达的极限!如果对超级大整数进行精确运算呢?一个简单的方法就是:仅仅使用现有的类型,但是把大整数的运算化为若干个小证书的运算,即所谓:“分块法”,原理如下图
本题关键在于理解分块乘法的原理
,原理中的分块很好理解,乘法也很好理解,难理解的是进位
r1 = m4, r2 = m2 + m3 + m4, r3 = m1 + m2 + m3, r4 = m1
的相加,因为m1 ~ m4这四个值是通过x1, x2, y1, y2组合相乘得来的,而x1, x2, y1, y2又是通过原有数值进行分块而来,所以这个相加并不简单。不简单在于这里需要回归 + 进位
,可以注意到图中有每一个mn都有两个,为什么?因为它们对应分块时的前段和后段,所以rn的取值应该先回归
,然后还需要对每一部分的结果进行进位
回归
到前段的队伍中,反之亦然举个例子
X = 23, Y= 34, 分两段,以10为界
r2 = r2 + r3 / 10 = 6 + 1 = 7
r3 = r3 % 10 = 18 % 10 = 8
r1 = r1 + r2 / 10 = 0 + 6 / 10 = 0
r2 = r2 % 10 = 6 % 10 = 6
r1r2r3r4 = 0782
void MultiLargeNumbers(int i_uXnum, int i_uYnum, int i_uBase)
{
vector<int> res(4, 0);
/* 1. 获取各部分小数 */
int x1 = i_uXnum % i_uBase;
int x2 = i_uXnum / i_uBase;
int y1 = i_uYnum % i_uBase;
int y2 = i_uYnum / i_uBase;
/* 2. 获取m1, m2, m3, m4 的值 */
int m1 = x1 * y1;
int m2 = x2 * y1;
int m3 = x1 * y2;
int m4 = x2 * y2;
/* 3. 保存r1, r2, r3, r4 的初步结果 */
res[0] = m4 / i_uBase;
res[1] = m2 / i_uBase + m3 / i_uBase + m4 % i_uBase;
res[2] = m1 / i_uBase + m2 % i_uBase + m3 % i_uBase;
res[3] = m1 % i_uBase;
/* 4. 根据乘积,进行进位处理 */
res[1] += res[2] / i_uBase;
res[2] %= i_uBase;
res[0] += res[1] / i_uBase;
res[1] %= i_uBase;
/* 5. 输出最后结果 */
cout << "Final result = [" << res[0] << res[1] << res[2] << res[3] << "]" << endl;
}