高精度加法和减法

高精度加法

在C/C++中,我们经常会碰到限定数据范围的情况,我们先来看看常用的int和long long两种数据类型的范围吧。
C++标准规定:int占一个机器字长。在32位系统中int占32位,即4个字节,所以int的范围是[-2的31次方,2的31次方-1],为1e8数量级;longlong的范围则是[-2的63次方,2的63次方-1],为1e18数量级。如果超过该数量级,该怎么办?
此时就需要用到高精度算法

输入两个整数a,b输出他们的和(a,b<=10的500次方)

这时我们只能使用高精度来解决

高精度加法的核心思想:

1.将大数分解成每一位的数字: 将大数按位分解为数组或字符串形式,使得可以逐位进行加法操作。通常情况下,数字的每一位都会以逆序存储(即个位在前),方便进行加法。
2.逐位加法: 从最低位开始进行加法。对于每一位,计算对应的数字之和,并处理进位。进位可能会影响到下一位的计算,因此需要将进位信息传递到下一位。
3.处理进位: 每一位的计算可能会产生进位,需要将进位加到下一位的计算中。
4.去除前导零: 计算完所有位后,结果可能会有前导零,需要去除这些零以得到最终的结果。

高精度加法的步骤:

1.初始化:

创建足够大的数组来存储每一位的结果,通常比输入数字的长度多一个位置以处理进位。

2.数字转换:

将输入的大数(字符串形式)转换为数字形式,并存储在数组中。由于我们处理的数字是逆序存储的,个位在数组的第一个位置。

3.执行加法:

从最低位(数组的第一个位置)开始,对每一位进行加法操作。计算每一位的和,并存储在结果数组中,同时处理进位。

4.处理进位:

每次加法操作后,计算进位并将其加到下一位的计算中。

5.去除前导零:

检查结果数组中是否有前导零,并将其去除。

6.输出结果:

从结果数组中输出高精度加法的结果,通常是从数组的最后一个有效位置(最高位)开始输出。
在这里插入图片描述
我们来看一道题这道题就运用了高精度加法
代码如下:

#include <iostream>
#include <cstring>  // 用于 strlen 函数
#include <algorithm> // 用于 max 函数
using namespace std;

char s1[505], s2[505]; // 存储输入的大数
int a[505], b[505], c[505]; // 存储数字形式的输入和结果

int main()
{
    int la, lb, lc; // s1、s2 和结果数组的长度

    // 读取两个大数作为字符串
    cin >> s1;
    cin >> s2;

    // 获取两个输入字符串的长度
    la = strlen(s1);
    lb = strlen(s2);

    // 将 s1 的字符转换为整数,并以逆序存储到数组 a 中
    for (int i = 0; i < la; i++)
    {
        a[la - i] = s1[i] - '0'; // 通过减去 '0' 将字符转换为整数
    }

    // 将 s2 的字符转换为整数,并以逆序存储到数组 b 中
    for (int i = 0; i < lb; i++)
    {
        b[lb - i] = s2[i] - '0'; // 通过减去 '0' 将字符转换为整数
    }

    // 确定结果数组的最大长度,加一是为了处理可能的进位
    lc = max(la, lb) + 1;

    // 逐位进行加法运算
    for (int i = 1; i <= lc; i++)
    {
        c[i] += a[i] + b[i]; // 将对应位的数字和进位相加
        c[i + 1] = c[i] / 10; // 计算进位
        c[i] = c[i] % 10; // 当前位的结果
    }

    // 移除结果数组中的前导零
    if (c[lc] == 0 && lc > 0)
    {
        lc--;
    }

    // 从最高位到最低位打印结果
    for (int i = lc; i > 0; i--)
    {
        cout << c[i]; // 打印结果的每一位
    }

    return 0;
}

下面是用y总模板写的

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 使用向量实现高精度加法
vector<int> add(vector<int> &A, vector<int> &B)
{
    // 确保 A 总是比 B 长(长度可能不同)
    if (A.size() < B.size()) return add(B, A);

    vector<int> C; // 存储结果的向量
    int carry = 0; // 存储当前位的进位
    
    // 遍历 A 中的每一位
    for (int i = 0; i < A.size(); i++)
    {
        carry += A[i]; // 将 A 的当前位加到 carry 中
        if (i < B.size()) carry += B[i]; // 如果 B 还有相应位,加上 B 的当前位
        
        C.push_back(carry % 10); // 当前位的结果是 carry 除以 10 的余数
        carry /= 10; // 更新进位 carry,即 carry 除以 10 的商
    }

    // 如果最后还有进位 carry,则将其添加到结果中
    if (carry) C.push_back(carry);

    return C; // 返回结果
}

int main()
{
    string s1, s2;
    cin >> s1 >> s2;

    // 将输入字符串转换为向量(每个字符转换为整数,且逆序存储)
    vector<int> A(s1.size()), B(s2.size());
    for (int i = 0; i < s1.size(); i++) {
        A[s1.size() - 1 - i] = s1[i] - '0';
    }
    for (int i = 0; i < s2.size(); i++) {
        B[s2.size() - 1 - i] = s2[i] - '0';
    }

    // 调用加法函数得到结果
    vector<int> C = add(A, B);

    // 去除前导零并输出结果
    int start = C.size() - 1;
    while (start > 0 && C[start] == 0) {
        start--;
    }

    for (int i = start; i >= 0; i--) {
        cout << C[i];
    }
    cout << endl;

    return 0;
}

高精度加法模板

模板来自于y总

#include <vector>
using namespace std;
// C = A + B, A >= 0, B >= 0
vector<int> add(vector<int> &A, vector<int> &B)
{
    // 确保 A 总是比 B 长(长度可能不同)
    if (A.size() < B.size()) return add(B, A);
    vector<int> C; // 存储结果的数组
    int t = 0;     // 存储当前位的和以及进位
    // 遍历 A 中的每一位
    for (int i = 0; i < A.size(); i ++ )
    {
        t += A[i]; // 将 A 的当前位加到 t 中
        if (i < B.size()) t += B[i]; // 如果 B 还有相应位,加上 B 的当前位
        
        C.push_back(t % 10); // 当前位的结果是 t 除以 10 的余数
        t /= 10; // 更新进位 t,即 t 除以 10 的商
    }
    // 如果最后还有进位 t,则将其添加到结果中
    if (t) C.push_back(t);
    return C; // 返回结果
}

高精度减法

基本步骤

1. 数的表示方式

由于普通数据类型不能表示超大整数,高精度减法通常将两个大数以字符串或数组的形式存储。每一位数字分别存储到字符串或数组的元素中,从而避免溢出的问题。

2. 确定符号与大小

在进行减法之前,首先要确定两个大数的大小,判断被减数和减数的相对大小,以确保不会出现负数。
如果被减数小于减数,那么结果为负数,符号应在结果前加上负号。
如果被减数大于或等于减数,则可以直接进行相减操作。

3. 位对位相减

高精度减法的核心是模仿我们平常手算的逐位相减:
从最低位(即末尾)开始,依次对每一位进行减法运算。
如果当前位的被减数小于减数,需要向高位借位,将高位的值减1,当前位的值加上10再进行减法。
重复这个过程,直到所有位都减完。

4. 处理借位

当某一位的减数大于被减数时,就需要从高位借位。这一步骤的难点在于需要处理连续的借位情况:
若上一位需要借位,则本位需减1,并继续判断是否需要继续借位。

5. 去除前导零

计算完所有位后,可能会出现前导零(如1000 - 999 = 0001)。此时需要去掉这些前导零,确保结果的格式正确。
在这里插入图片描述
我们来看一道题这道题就运用了高精度减法
代码如下:

#include<iostream>
#include<cstring>  // 用于strlen, strcpy等字符串处理函数
using namespace std;

char s1[10090], s2[10090], s3[10090];  // 字符数组用于存储输入的两个字符串以及临时交换用的字符串
int a[10090], b[10090], c[10090];      // 数组a, b分别存储字符串s1和s2的数字表示,c存储结果
int flag = 0;                          // 标志变量,用于判断是否需要输出负号

// 比较两个字符串表示的数值大小,如果s1 >= s2返回true,否则返回false
bool compare(char s1[], char s2[])
{
    int u = strlen(s1), v = strlen(s2);   // 获取s1和s2的长度
    if (u != v)                          // 如果长度不同,则长度大的数更大
    {
        return u > v;
    }
    for (int i = 0; i < u; i++)          // 长度相同的情况下,逐位比较
    {
        if (s1[i] != s2[i])              // 如果某一位不同,则返回该位较大的结果
        {
            return s1[i] > s2[i];
        }
    }
    return true;                         // 如果所有位都相同,s1 == s2,返回true
}

int main()
{
    int la, lb, lc;   // 定义变量存储s1、s2的长度以及最终结果的位数
    cin >> s1 >> s2;  // 输入两个字符串表示的大数

    // 如果s1 < s2,交换s1和s2,使得大数在前
    if (!compare(s1, s2))
    {
        flag = 1;                // 标志置为1,表示需要输出负号
        strcpy(s3, s1);          // 用临时数组s3保存s1的值
        strcpy(s1, s2);          // 将s2赋值给s1
        strcpy(s2, s3);          // 将临时数组s3的值赋给s2,完成交换
    }

    la = strlen(s1);  // 获取s1的长度
    lb = strlen(s2);  // 获取s2的长度

    // 将s1和s2的字符转为数字并倒序存入a和b数组
    for (int i = 0; i < la; i++)
    {
        a[la - i] = s1[i] - '0';  // 将s1的第i个字符转为数字,倒序存入a
    }
    for (int i = 0; i < lb; i++)
    {
        b[lb - i] = s2[i] - '0';  // 将s2的第i个字符转为数字,倒序存入b
    }

    lc = max(la, lb);  // lc是结果的最大可能位数,即la和lb中的最大值

    // 从低位到高位进行逐位减法
    for (int i = 1; i <= lc; i++)
    {
        if (a[i] < b[i])   // 如果当前位a[i]小于b[i],需要向高位借位
        {
            a[i + 1]--;    // 向高位借1
            a[i] += 10;    // 当前位加10
        }
        c[i] = a[i] - b[i];  // 计算当前位的差值并存入c数组
    }

    // 去掉前导零
    while (c[lc] == 0 && lc > 1)
    {
        lc--;  // 如果最高位是0,且lc > 1,则将lc减1
    }

    // 如果flag标志为1,说明s1 < s2,需要输出负号
    if (flag == 1)
    {
        cout << '-';
    }

    // 输出结果,从最高位输出到最低位
    for (int i = lc; i > 0; i--)
    {
        cout << c[i];
    }

    return 0;
}

下面代码用y总模板写的

#include<iostream>
#include<vector>
#include<string>

using namespace std;

// 大数减法函数,计算 C = A - B,前提条件是 A >= B
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;  // 定义一个vector C,用于存储结果
    for (int i = 0, t = 0; i < A.size(); i++)  // 从A的最低位到最高位遍历,t表示借位
    {
        t = A[i] - t;  // 当前位A[i]减去上一次的借位t
        if (i < B.size()) t -= B[i];  // 如果当前位i在B范围内,则从t中再减去B[i]
        
        // 处理当前位的差值,并将结果存入C
        // (t + 10) % 10 确保结果在0到9之间,处理借位情况
        C.push_back((t + 10) % 10);  

        // 如果t小于0,说明借位发生,设置t为1表示向下一位借位
        // 否则t为0,不需要借位
        if (t < 0) t = 1;
        else t = 0;
    }

    // 去掉结果C中的前导零,如果C的长度大于1,且最后一位是0,则将其删除
    while (C.size() > 1 && C.back() == 0) C.pop_back();

    return C;  // 返回存储结果的vector C
}

// 比较两个大数 A 和 B,如果 A >= B 返回 true,否则返回 false
bool cmp(const vector<int>& A, const vector<int>& B)
{
    if (A.size() != B.size()) return A.size() > B.size();  // 位数不同则直接比较位数
    for (int i = A.size() - 1; i >= 0; i--)  // 从高位到低位逐位比较
    {
        if (A[i] != B[i]) return A[i] > B[i];
    }
    return true;  // 如果每一位都相同,则 A == B
}

int main()
{
    string s1, s2;
    cin >> s1 >> s2;

    // 将字符串 s1 和 s2 转换为数字存储在 A 和 B 中,倒序存储以便逐位计算
    vector<int> A(s1.size()), B(s2.size());
    for (int i = 0; i < s1.size(); i++)
    {
        A[s1.size() - 1 - i] = s1[i] - '0';  // 倒序存储 s1 中的数字
    }
    for (int i = 0; i < s2.size(); i++)
    {
        B[s2.size() - 1 - i] = s2[i] - '0';  // 倒序存储 s2 中的数字
    }

    bool isNegative = false;  // 记录最终结果是否为负数
    if (!cmp(A, B))  // 如果 A < B,则交换 A 和 B,确保 A >= B
    {
        swap(A, B);
        isNegative = true;  // 结果是负数
    }

    // 调用大数减法函数
    vector<int> C = sub(A, B);

    // 输出结果,去掉前导零
    if (isNegative) cout << '-';  // 如果结果是负数,输出负号
    for (int i = C.size() - 1; i >= 0; i--)
    {
        cout << C[i];
    }

    cout << endl;

    return 0;
}

高精度减法模板

// 计算C = A - B,其中A >= B,且A和B都是非负整数
vector<int> sub(vector<int> &A, vector<int> &B)
{
    vector<int> C;  // 定义一个vector C,用于存储结果
    for (int i = 0, t = 0; i < A.size(); i++)  // 从A的最低位到最高位遍历,t表示借位
    {
        t = A[i] - t;  // 当前位A[i]减去上一次的借位t
        if (i < B.size()) t -= B[i];  // 如果当前位i在B范围内,则从t中再减去B[i]
        
        // 处理当前位的差值,并将结果存入C
        // (t + 10) % 10 确保结果在0到9之间,处理借位情况
        C.push_back((t + 10) % 10);  

        // 如果t小于0,说明借位发生,设置t为1表示向下一位借位
        // 否则t为0,不需要借位
        if (t < 0) t = 1;
        else t = 0;
    }

    // 去掉结果C中的前导零,如果C的长度大于1,且最后一位是0,则将其删除
    while (C.size() > 1 && C.back() == 0) C.pop_back();

    return C;  // 返回存储结果的vector C
}

gitee源码

好的,下面是同时实现高精度加法减法C++代码: ```cpp #include <iostream> #include <string> #include <algorithm> using namespace std; // 高精度加法 string add(string num1, string num2) { // 先将两个数的位数补齐 int len1 = num1.length(), len2 = num2.length(); if (len1 < len2) { num1 = string(len2 - len1, '0') + num1; len1 = len2; } else { num2 = string(len1 - len2, '0') + num2; len2 = len1; } // 从低位到高位逐位相加 string result = ""; int carry = 0; for (int i = len1 - 1; i >= 0; i--) { int sum = num1[i] - '0' + num2[i] - '0' + carry; carry = sum / 10; result += to_string(sum % 10); } // 如果还有进位,需要在高位加上进位的1 if (carry == 1) { result += "1"; } // 将结果翻转过来 reverse(result.begin(), result.end()); // 去掉前导0 int pos = 0; while (pos < result.length() && result[pos] == '0') { pos++; } result = result.substr(pos); if (result.empty()) { result = "0"; } return result; } // 高精度减法 string subtract(string num1, string num2) { // 先将两个数的位数补齐 int len1 = num1.length(), len2 = num2.length(); if (len1 < len2) { num1 = string(len2 - len1, '0') + num1; len1 = len2; } else { num2 = string(len1 - len2, '0') + num2; len2 = len1; } // 从低位到高位逐位相减 string result = ""; int borrow = 0; for (int i = len1 - 1; i >= 0; i--) { int diff = num1[i] - num2[i] - borrow; if (diff < 0) { diff += 10; borrow = 1; } else { borrow = 0; } result += to_string(diff); } // 去掉前导0 reverse(result.begin(), result.end()); int pos = 0; while (pos < len1 && result[pos] == '0') { pos++; } result = result.substr(pos); if (result.empty()) { result = "0"; } // 判断结果是否为负数 if (borrow == 1) { result = "-" + result; } return result; } int main() { string num1, num2, op; cin >> num1 >> op >> num2; // 根据运算符进行相应的运算 if (op == "+") { cout << add(num1, num2) << endl; } else if (op == "-") { cout << subtract(num1, num2) << endl; } else { cout << "Invalid operator!" << endl; } return 0; } ``` 这里同时实现了高精度加法函数 `add` 和高精度减法函数 `subtract`。在输入部分和之前一样,使用了 `cin` 来读取输入的两个数字和运算符。然后根据运算符进行相应的运算,并输出结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值