高精度加法和减法

高精度加法

在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赋值给s1strcpy(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]--;    // 向高位借1a[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]减去上一次的借位tif (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]减去上一次的借位tif (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源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/142965.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

独立站技能树之建站33项自检清单 1.0丨出海笔记

很多时候大家建好站之后很嗨&#xff0c;但过一会就开始担忧各种纠结我是不是还有什么点没做好&#xff0c;或者我的站漏了什么东西&#xff0c;那么接下来以下这个独立站自检清单能很好的帮到你。其实对于新手我还是建议大家直接用一些模板&#xff0c;因为模板上面基本该有的…

基于SpringBoot+Vue+MySQL的在线招投标系统

系统展示 用户前台界面 管理员后台界面 系统背景 在当今商业环境中&#xff0c;招投标活动是企业获取项目、资源及合作伙伴的重要途径。然而&#xff0c;传统招投标过程往往繁琐复杂&#xff0c;涉及众多文件交换、信息审核与沟通环节&#xff0c;不仅效率低下&#xff0c;还易…

车市状态喜人,国内海外“两开花”

文/王俣祺 导语&#xff1a;随着中秋假期告一段落&#xff0c;“金九”也正式过半&#xff0c;整体上这个销售旺季的数据可以说十分喜人&#xff0c;各家车企不是发布新车、改款车就是推出了一系列购车权益&#xff0c;充分刺激了消费者的购车热情。再加上政府政策的鼎力支持&a…

动态线程池实战(一)

动态线程池 对项目的认知 为什么需要动态线程池 DynamicTp简介 接入步骤 功能介绍 模块划分 代码结构介绍

中、美、德、日制造业理念差异

合格的产品依赖稳定可靠的人机料法环&#xff0c;要求减少变量因素&#xff0c;增加稳定因素&#xff0c;避免“熵”增&#xff1b;五个因素中任何一个不可控&#xff0c;批次产品的一致性绝对差&#xff1b; 日本汽车企业&#xff0c;侧重“人”和“环”&#xff0c; 倚重是人…

828华为云征文|华为云Flexus云服务器X实例之openEuler系统下部署SQLite数据库浏览器sqlite-web

828华为云征文&#xff5c;华为云Flexus云服务器X实例之openEuler系统下部署SQLite数据库浏览器sqlite-web 前言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、sqlite-web介绍2.1 sqlite-web简介2.2…

画台扇-第15届蓝桥省赛Scratch中级组真题第3题

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第188讲。 如果想持续关注Scratch蓝桥真题解读&#xff0c;可以点击《Scratch蓝桥杯历年真题》并订阅合集&#xff0c;…

【教程】鸿蒙ARKTS 打造数据驾驶舱---前序

鸿蒙ARKTS 打造数据驾驶舱 ​ 前面2章我介绍了如何通过定义View绘制箭头以及圆形进度&#xff0c;初步了解了鸿蒙如何进行自定义View。接下来我将通过我最近在带的一个VUE的项目&#xff0c;简单实现了几个鸿蒙原生页面。帮助大家快速上手纯血鸿蒙开发. 本项目基于Api11Stage模…

揭开GPRC5D靶点的神秘面纱,助力多发性骨髓瘤药物开发

前 言 多发性骨髓瘤属于第二大常见的血液系统恶性肿瘤&#xff0c;起源于骨髓造血组织的浆细胞恶性增殖。首发症状表现为非特异性&#xff0c;如腰疼、反复感染等&#xff0c;造成误诊、漏诊率较高&#xff0c;且难治愈易复发。目前临床上的治疗有靶向治疗、放疗、化疗、干细…

C++之继承(通俗易懂版)

前言&#xff1a;我们都知道C是一门支持过程化编程&#xff0c;面向对象的高级语言&#xff0c;既然是面向对象的语言&#xff0c;那么对于对象而言&#xff0c;对象会有很多中相同的属性&#xff0c;举个例子:你和你老师&#xff0c;你们都有着共同的属性和身份&#xff0c;例…

Linux--守护进程与会话

进程组 概念 进程组就是一个或多个进程的集合。 一个进程组可以包含多个进程。 下面我们通过一句简单的命令行来展示&#xff1a; 为什么会有进程组&#xff1f; 批量操作&#xff1a;进程组允许将多个进程组织在一起&#xff0c;形成一个逻辑上的整体。当需要对多个进程…

【关联规则】【Apriori算法】理解

关联规则学习是数据挖掘中的一种技术&#xff0c;用于发现大型数据库中变量间的有趣关系&#xff0c;特别是变量之间的有意义的关联、相关和依赖关系。这种类型的规则在零售业中特别有用&#xff0c;因为它可以帮助确定哪些商品经常一起购买。 关键概念 频繁项集&#xff08;F…

连锁会员管理系统应该有的高级功能

会员连锁管理系统是一种专门针对连锁企业设计的会员管理软件&#xff0c;它可以帮助连锁企业实现跨区域、跨店铺的会员信息、消费记录和积分等的统一管理。以下分析商淘云连锁会员管理系统的主要功能。 会员信息管理&#xff1a;全面收集和管理会员信息&#xff0c;如手机号码、…

2.4 卷积1

2.4 卷积1 2.4 卷积 在了解了系统及其脉冲响应之后&#xff0c;人们可能会想知道是否有一种方法可以通过任何给定的输入信号&#xff08;不仅仅是单位脉冲&#xff09;确定系统的输出信号。卷积就是这个问题的答案&#xff0c;前提是系统是线性且时不变的&#xff08;LTI&…

不用价位宠物空气净化器有什么区别?性价比高宠物空气净化器推荐

自新冠之后&#xff0c;越来越多人意识到优质空气对健康的重要性了&#xff0c;纷纷购置了空气净化器。不少铲屎官便关注到了“宠物空气净化器”这一专业品牌&#xff0c;但越后面入手宠物空气净化器的人&#xff0c;看到的品牌越多。整个市场那是个“蓬勃发展”。 随着消费者…

erlang学习:mnesia数据库与ets表1

Mnesia 和 ETS 都是 Erlang 提供的表管理工具&#xff0c;用于存储和检索数据&#xff0c;但它们之间有一些重要的区别和共同点。 共同点 都是Erlang提供的表存储机制&#xff1a;ETS 和 Mnesia 都允许你在内存中创建表&#xff0c;并且可以用来存储键值对或者更复杂的数据结…

高级大数据开发协会

知识星球——高级大数据开发协会 协会内容: 教你参与开源项目提供新技术学习指导提供工作遇到的疑难问题技术支持参与大数据开源软件源码提升优化以互利共赢为原则&#xff0c;推动大数据技术发展探讨大数据职业发展和规划共享企业实际工作经验 感兴趣的私聊我&#xff0c;…

我要走遍三山五岳之---嵩山

文章目录 嵩山通勤开爬总结 嵩山 2024.9.16登顶第一座五岳。 为啥第一座高山选择了嵩山呢&#xff1f;因为本来就是新手&#xff0c;想选择一个低难度的开始爬。看了小红书上的攻略&#xff0c;五岳的难度&#xff1a;华山>泰山>嵩山>衡山>恒山。 本来想选择的是…

Linux常见查看文件命令

目录 一、cat 1.1. 查看文件内容 1.2. 创建文件 1.3. 追加内容到文件 1.4. 连接文件 1.5. 显示多个文件的内容 1.6. 使用管道 1.7. 查看文件的最后几行 1.8. 使用 -n 选项显示行号 1.9. 使用 -b 选项仅显示非空行的行号 二、tac 三、less 四、more 五、head 六、…

GAMES101(10~11节,几何)

Geometry implicit隐式几何表示&#xff1a; 函数f(x,y,z)&#xff1a; 根据函数fn描述几何&#xff0c;遍历所有空间内 的点&#xff0c;如果带入xyz到函数f(x,y,z)结果0那就绘制这个点 如果xyz求值结果>0表示在几何外&#xff0c;0在表面,<0在几何内 构造几何csg(…