《算法竞赛从入门到国奖》算法基础:入门篇-高精度

💡Yupureki:个人主页

✨个人专栏:《C++》 《算法》


🌸Yupureki🌸的简介:


目录

前言

[1. 高精度加法](#1. 高精度加法)

算法原理

实操代码

[2. 高精度减法](#2. 高精度减法)

算法原理

实操代码

[3. 高精度乘法](#3. 高精度乘法)

算法原理

实操代码

[4. 高精度除法](#4. 高精度除法)

算法原理

实操代码


前言

当数据范围极其之大,甚至超过了long long的存储范围时,我们需要利用字符串来进行加减乘除的运算。因此我们需要先利用字符串存储数据,随后模拟数学中加减乘除的过程。这一算法称之为大数运算,也就是高精度运算

1. 高精度加法

题目链接:

P1601 A+B Problem(高精) - 洛谷

算法原理

我们会发现数据范围为10的18次方,对于这么大的数字,我们利用整型来存储肯定是不合适的,因此得用字符串,也就是string存储,然后进行加法

那么如何进行字符串之间的加法?我们回想小学学过的竖式乘法

首先便是对应位相加,例如上面6 + 3得9,2+8得10,注意此时相加的10已经超过9了,我们得处理进位,因此留下0,在1+4中需要加上进位1得6,最后得到609。

此时有个小细节,即相加是从最低位开始的,即个位相加后再十位相加

那么对于字符串"123"和"486"相加,我们也得从最后面,即3和6相加开始,但是从后往前加有点不爽,这里我选择把两个字符串倒置,得到"321"和"684",这样从每个字符串开头相加就可以了,得到字符串"906",此时结果字符串仍是倒置的,我们再次倒置得到"609"即可

实操代码

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string a, b; cin >> a >> b;
    reverse(a.begin(), a.end());//倒置两个字符串
    reverse(b.begin(), b.end());
    int forward = 0;//初始时进位设置为0
    int left = 0;
    string ret;
    int i = 0;
    while (i < a.size() || i < b.size())
    {
        int n = 0; int m = 0;
        if (i < a.size())
            n = a[i] - '0';
        if (i < b.size())
            m = b[i] - '0';
        left = (n + m + forward) % 10;//处理余数
        ret += left + '0';
        forward = (n + m + forward) / 10;;//处理进位
        i++;
    }
    if (forward)//别忘了处理最后的进位
        ret += forward + '0';
    reverse(ret.begin(), ret.end());
    cout << ret;
    return 0;
}

2. 高精度减法

题目链接:

P2142 高精度减法 - 洛谷

算法原理

跟小学数学一样,我们模拟竖式减法即可

但过程中如果第一个数小于第二个数,可能会出现减法。这里为了方便,我们始终让大数减去小数得到正数,如果第一个数较小,最后多加个负号即可

依然是从个位开始,对应位相减,如果不够,那么从高位借一即可

实操代码

cpp 复制代码
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string a, b; cin >> a >> b;
    string ret;
    if (b.size() > a.size() || (a.size() == b.size() && a < b))
    {
        cout << "-";
        swap(a, b);//保持较大数减较小数
    }
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    int i = 0;
    while (i < a.size() || i < b.size())
    {
        int n = 0; int m = 0;
        if (i < a.size())
            n = a[i] - '0';
        if (i < b.size())
            m = b[i] - '0';
        int left = n - m;
        if (left < 0)
        {
            left += 10;//向高位借1
            a[i + 1]--;
        }
        ret += left + '0';
        i++;
    }
    reverse(ret.begin(), ret.end());
    auto it = ret.begin();
    while (it != ret.end() && *it == '0')
        it++;
    if (it == ret.end())
        cout << "0";
    else
    {
        while (it != ret.end())
        {
            cout << *it;
            it++;
        }
    }
    return 0;
}

3. 高精度乘法

题目链接:

P1303 A*B Problem - 洛谷

算法原理

依然是模拟小学的竖式相乘,但较麻烦的是,乘法很容易出现二位数,因此需要频繁地进行进位处理,这里为了方便,我们不进位,到最后相乘完再进位

例如在这里,我们不进行进位操作,对于每一位我们直接相加得到最后的结果,最后再进位

当然也有个小细节,相乘的结果估计会很大,我们需要预设一个较大的数组来存储,但是这样也有可能导致数组有部分空间是空出来的,最后得到的字符串前面会有很多无效0,例如0000887112,因此我们需要在最后去除这些前导0

实操代码

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;

int main()
{
    string a, b; cin >> a >> b;
    vector<int> v(a.size() + b.size(), 0);
    reverse(a.begin(), a.end());
    reverse(b.begin(), b.end());
    for (int i = 0; i < a.size(); i++)
    {
        for (int j = 0; j < b.size(); j++)
        {
            int num = (a[i] - '0') * (b[j] - '0');
            v[i + j] += num;//不处理进位,直接相加
        }
    }
    int forward = 0;
    int left = 0;
    for (int i = 0; i < v.size(); i++)
    {
        left = (forward + v[i]) % 10;
        forward = (forward + v[i]) / 10;
        v[i] = left;
    }
    reverse(v.begin(), v.end());
    auto it = v.begin();
    while (it != v.end() && *it == 0)
        it++;
    if (it == v.end())
        cout << "0";
    else
    {
        while (it != v.end())
        {
            cout << *it;
            it++;
        }
    }
    return 0;
}

4. 高精度除法

题目链接:

P1480 A/B Problem - 洛谷

算法原理

我们依然模拟小学学过的除法,但是这次我们是从最高位开始除,因此我们无需倒置字符串

最后得到的字符串前面也有0,因此我们需要处理这些前导0

实操代码

cpp 复制代码
#include <string>
#include <algorithm>
using namespace std;

int main()
{
    string a;int b;cin>>a>>b;
    string ret;
    long long left = 0;
    for(int i = 0;i<a.size();i++)
    {
        long long num = a[i] - '0' + left*10;
        ret += (num/b) +'0';
        left = num % b;
    }
    auto it  = ret.begin();
    while(it != ret.end() && *it == '0')
        it++;
    if(it == ret.end())
        cout<<"0";
    else
    {
        while(it != ret.end())
        {
            cout<<*it;
            it++;
        }
    }
    return 0;
}
相关推荐
2的n次方_5 小时前
CANN Ascend C 编程语言深度解析:异构并行架构、显式存储层级与指令级精细化控制机制
c语言·开发语言·架构
iAkuya5 小时前
(leetcode)力扣100 62N皇后问题 (普通回溯(使用set存储),位运算回溯)
算法·leetcode·职场和发展
近津薪荼5 小时前
dfs专题5——(二叉搜索树中第 K 小的元素)
c++·学习·算法·深度优先
xiaoye-duck5 小时前
吃透 C++ STL list:从基础使用到特性对比,解锁链表容器高效用法
c++·算法·stl
松☆5 小时前
CANN与大模型推理:在边缘端高效运行7B参数语言模型的实践指南
人工智能·算法·语言模型
_F_y5 小时前
C++重点知识总结
java·jvm·c++
java干货5 小时前
为什么 “File 10“ 排在 “File 2“ 前面?解决文件名排序的终极算法:自然排序
开发语言·python·算法
_F_y5 小时前
C语言重点知识总结(含KMP详细讲解)
c语言·开发语言
皮皮哎哟5 小时前
数据结构:嵌入式常用排序与查找算法精讲
数据结构·算法·排序算法·二分查找·快速排序
程序员清洒5 小时前
CANN模型剪枝:从敏感度感知到硬件稀疏加速的全链路压缩实战
算法·机器学习·剪枝