高精度乘法.概述

一、高精度乘法(高精乘低精)

与高精度加法与减法类似,高精度的乘法,我们依然是按照“竖式运算”的原理进行计算。例如:

#include<bits/stdc++.h>
using namespace std;
string s1;
int b,flaga,flagb;
int a[100005];
int main()
{
    cin>>s1>>b;
    if ('-'==s1[0])
	{
		flaga = true;
		s1.erase(s1.begin());//删除负号
    }

    if(b<0)
    {
		flagb = true;
		b=-b;
    }

    if( flaga !=flagb )  //负负得正,正负得负,负正得负,正正得正 
		printf("-");

    int len=s1.size();
    for(int i=0;i<len/2;i++) //将字符串翻转
        swap(s1[i],s1[len-1-i]);


    int jw=0;
    for(int i=0;i<len;i++)
    {
		a[i]+=(s1[i]-'0')*b+jw;
		jw=a[i]/10;
		a[i]%=10;
    }

    if(jw>0)
    {
		a[len]=jw;	
		len++;
    }

    int t=0;
    for(int i=len-1;i>=0;i--)
		cout<<a[i];

    return 0;

}

二、高精度乘法(高精乘高精)

与高精度加法与减法类似,高精度的乘法,我们依然是按照“竖式运算”的原理进行计算。例如:

我们假设用数组A存储被乘数856的每一位,具体来说就是A0存储个位6,A1存储十位5,A2存储百位8;使用数组B存储乘数25,存储结构与数组A类似;使用数组C存储对应的乘积21400,存储结构与数组A类似,那么结果则如表格所示:

首先,我们不难推测

C0 = C’0 = A0 × B0;

C1 = C’1 + C”1 = A1 × B0 + B1 × A0 + 进位

C2 = C’2 + C”2 = A2 × B0 + B1 × A1 + 进位

C3 = C’3 + C”3 = A3 × B0 + B1 × A2 + 进位

...

根据规律我们可以总结特点

  1. a[i] × b[j] 的答案应该累加到 c[i+j] 的位置;
  2. 累加总结果为:c[i+j] += a[i] × b[j] + 进位
  3. 带入下一位累加的进位为c[i+j]/10,本位实际数为c[i+j]%=10

具体实现思路:

  1. 输入两个字符串,先将其进行预处理(将字符串中的数翻转后存入数组中);
  2. 先判断两个字符串所代表的数的正负情况,提前做好符号标记;
  3. 使用双重循环,分别求出a[i] × b[j] 的结果并累计到 c[i+j] 中;
  4. 进行下一位累加的进位计算并加起来,同时求出本位的实际数;
  5. 删除前导零;
  6. 求解完毕后,将乘积数组c反向输出。

思考:为什么高精度乘法不像之前的高精度加法与减法一样,之前从后面往前开始计算,而是要先进行预处理,将其翻转后再计算?

具体代码:

  1. 定义数组:
int MAXN = 1e5+4; //根据题目的最大值。+4为了防止A+B出现进位
string s1;//存储字符串
string s2;//存储字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[2*MAXN] = {};//存储乘积

  1. 读入数据,考虑处理正负数相乘的形式:
cin>>s1>>s2;//读入字符串

//处理负数
bool flaga = false;//乘数a的符号
if ('-'==s1[0]) {
	flaga = true;
	s1.erase(s1.begin());//删除负号
}

bool flagb = false;//乘数b的符号
if ('-'==s2[0]) {
	flagb = true;
	s2.erase(s2.begin());//删除负号
}

//处理输出的负号
if ((flaga != flagb) {
    printf("-");
}

//处理乘数1
int lena = s1.size();
for (int i=0; i<lena; i++) {
	a[lena-i-1]=s1[i]-'0'; 
}

//处理乘数2
int lenb = s2.size();
for (int i=0; i<lenb; i++) {
    b[lenb-i-1]=s2[i]-'0';
}

  1. 模拟竖式乘法运算
int jw;//上一轮计算进位
for (int i=0; i<lena; i++) {
	jw=0;
	for (int j=0; j<lenb; j++) {
        //交叉乘积
        c[i+j] = a[i]*b[j]+jw+c[i+j];//当前乘积+上次乘积进位+原数
        jw = c[i+j]/10;//处理进位
        c[i+j] %= 10;
    }
    c[i+lenb]=jw;//进位设置
}

  1. 删除前导零
int lenc=lena+lenb;
for (int i=lenc-1; i>=0; i--) {
    //因为我们是从索引 0 开始,所以最高位是保存在 len-1
    if (0==c[i] && lenc>1) {
        //注意要有 lenc>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
        lenc--;
    }
	else {
        //第一个不是零的最高位,结束删除
        break;
    }
}

  1. 输出计算结果
for (int i=lenc-1; i>=0; i--) {
    printf("%d", c[i]);
}
printf("\n");
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值