高精度笔记(2)乘除

不论是加减法还是乘除法,本质上都先从我们人类做这类题目的思路出发——列竖式。

然后我们再在人类方法的基础上做一些改进和优化,使得代码更加优雅。

先说乘法:

我们思考123*123,

列成竖式之后我们会先做3 * 123,然后2 * 123(原本是20不过我们通过改变竖式中的列数将这个20的0给省略了),然后1 * 123,最后把三个按照竖式的格式都加起来得到答案。

那么同样的,我们也可以让计算机从个位开始也像这样乘起来,比如3 * 123得到369,我们把末位的9塞到答案容器中去,然后把36整体看做是进位,加到下一步2*123的结果246上面去,然后将得到的和282的末位2塞到容器里9的后面,把28加到下一步中去,以此类推,我们得到了最终的答案。

需要注意的是,如果我们需要执行的是1234 * 0,那么像之前一样我们会让4 * 0,得到0塞到答案里,再让3 * 0得到0塞到答案里,像这样连塞4个0进去,答案就会变成0000,这显然不是我们想要的,我们只需要一个0就够了。所以我们需要增加一步来去除答案数组中排在有效数字之前的无效的0,这一步也被很多人称呼为去除先导0,这也是实战中常常会漏掉的一步。

以下为一道高精度乘法模板,要求背过:

#include <iostream>
#include <vector>
//纯手打
using namespace std;

vector <int> mul(vector <int> & A, int b) {
    vector <int> C;
    int t = 0;//设置进位
    for (int i = 0; i < A.size(); i ++) {
        t += A[i] * b;       // 3 * 123 = 369
        C.push_back(t % 10); // 取个位9
        t /= 10;             // 然后把36全看做进位
    }

    while (t) {            // 处理最后剩余的 t
        C.push_back(t % 10);
        t /= 10;
    }

    while (C.size() > 1 && C.back() == 0) C.pop_back();//去除先导0

    return C;
}

int main() {
    string a;
    int b;
    cin >> a >> b;//如123*123
    
    vector <int> A;
    for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');

    vector<int> C = mul(A, b);
    for (int i = C.size() - 1; i >= 0; i --) printf("%d",C[i]);
    return 0;
}

除法的做法也与之类似,我们列一个竖式,然后用相近的思维将过程转化为C++。

假设除数是b,被除数是,则我们会先将除以b,得到的商作为总答案商的第一位,然后将余数下移乘以十,加上,在将和除以b,得到的商作为总答案的第二位……以此类推。

需要注意的是,和乘法相同,我们也需要去除先导0。例如123 / 11,我们会先让1除以11,得到商为0余数为1,但是在我们人类的写法中一般省略这个0不会把他写到竖式上方去作为第一位,而是会直接找到不是0的那一位从那里开始做除法。在计算机的计算过程中,我们可以预见,按照我们之前设想的代码计算机会傻傻的把0都写上,变成123/11 = 011……2。因此我们需要执行去除先导0.

以下为一道高精度除法模板,要求背过:

#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;
//商是C,余数是r
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();//去除先导0
    return C;
}

int main() {
    string a;
    int b, r;
    cin >> a >> b;

    vector <int> A;
    for (int i = a.size() - 1; i >= 0; i --) A.push_back(a[i] - '0');

    vector<int> C = div(A, b, r);

    for (int i = C.size() - 1; i >= 0; i --) printf("%d",C[i]);
    cout << endl << r << endl; 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值