草庐IT

算法笔记——高精度算法(附源码)

热爱编程的小K 2023-09-08 原文

📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段,因为最近参加新星计划算法赛道(白佬),所以加快了脚步,果然急迫感会增加动力>——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的
📖作者主页:热爱编程的小K
📖专栏链接:算法笔记

🎉欢迎各位→点赞👏 + 收藏💞 + 留言🔔​
💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾


💯文章目录

✨一、高精度算法的应用场景

利用计算机进行数值计算,有时会遇到这样的问题:有些计算要求精度高,希望计算的数的位数可达几十位甚至几百位,虽然计算机的计算精度也算较高了,但因受到硬件的限制,往往达不到实际问题所要求的精度。我们可以利用程序设计的方法去实现这样的高精度计算。这里不包括java和Python选手哈,当输入很大的时候scanf比cin效率更高

✨二、高精度加法

1、思路

我们先手动模拟一下加法

  • 先个位相加:6+6=12,所以个位的结果得2,向十位进1

  • 再十位相加:6+9+1(进位)=16,所以十位的结果得6,向百位进1

  • 最后再百位相加:5+1(进位)=6,所以百位的结果得6,进位为0

2、算法

  • 第一步:需要把两个大整数倒序过来储存到一个数组中,因为我们都知道加法是从低位开始加的

  • 第二步:判断较长的数字,放在前面,因为循环条件需要

  • 第三步:开始计算A[i]+B[i]+t这里t表示进位,前面的和表示为sum,则当前的位的结果表示为sum%10,进位更新t/=10

  • 循环结束后:判断t为不为0,如果不为0,需要把t存到和数组中(这种情况就是和比最长加数还要长的情况)

3、模板展示

vector<int> add(vector<int> &A, vector<int> &B)
{
    if (A.size() < B.size()) return add(B, A);
    //为了方便计算,让A中保存较长的数字, B中保存较短的数字

    vector<int> C;//保存结果的数组
    int t = 0;//进位,开始时是0
    for (int i = 0; i < A.size(); i ++ )//依次计算每一位
    {
        t += A[i];//加上 A 的第 i 位上的数字
        if (i < B.size()) t += B[i];//加上 B 的第 i 位上的数字
        C.push_back(t % 10); //C 中放入结果
        t /= 10;//t 更新成进位
    }

    if (t) C.push_back(t);//最后如果进位上有数,放进结果数组
    return C;//返回结果
}

💖4、习题练习

1、题目:Acwing 791. 高精度加法

给定两个正整数(不含前导 0),计算它们的和。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的和。

数据范围

1≤整数长度≤100000

输入样例:
12
23
输出样例:
35
2、代码展示
#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector<int> add(vector<int>&A,vector<int>&B)
{
    vector<int> C;
    if(A.size()<B.size()) return add(B,A);//大的放前面,判断
    int t=0;//进位
    for(int i=0;i<A.size();i++)
    {
        t+=A[i];
        if(i<B.size()) t+=B[i];
        C.push_back(t%10);
        t/=10;
    }
    if(t) C.push_back(t);
    return C;
    
}
int main()
{
    string a,b;
    vector<int> A,B;
    cin>>a>>b;
    //倒序存放
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    for(int i=b.size()-1;i>=0;i--) B.push_back(b[i]-'0');
    auto C=add(A,B);
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    cout<<endl;
    return 0;
}

✨三、高精度减法

1、思路

一样的我们先模拟一下减法竖式

  • 和高精度加法差不多,值得注意的是
  • 减法的借位处理
  • 相减为负数的处理
  • 前导0的处理

2、算法

  • 对于两个减数的处理t = A[i] - B[i] - t; 可以拆为 t = A[i] - t如果B[i]合法,再t -= B[i] 这么两步来做,这里的t表示借位
  • 两数对应位置相减后放入的应为(t+10)%10解释:t>0时,对应位的结果就为t,t<0时,对应结果为t-10,借位
  • 相减为负数的处理:加一个判断大小的函数,大的当减数,小的当被减数,为负的情况最后再输出的时候再先输出一个负号

3、模板展示

vector<int> sub(vector<int>&A,vector<int>&B)
{
    vector<int> C;
    int t=0;
    for(int i=0;i<A.size();i++)
    {
        t=A[i]-t;
        if(i<B.size()) t-=B[i];
        C.push_back((t+10)%10);
        //借位处理
        if(t<0) t=1; 
        else t=0;
    }
    //前导0处理
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
}

💖 4、习题练习

1、题目 Acwing 792. 高精度减法

给定两个正整数(不含前导 00),计算它们的差,计算结果可能为负数。

输入格式

共两行,每行包含一个整数。

输出格式

共一行,包含所求的差。

数据范围

1≤整数长度≤10的5次方

输入样例:
32
11
输出样例:
21
2、代码展示
#include <iostream>
#include <vector>
using namespace std;
bool cmp(vector <int> &A,vector <int> &B)
{ 
    // 判断是否A > B
    if(A.size() != B.size()) return A.size() > B.size(); 
    // 如果A、B长度不相同,长度长的那个数大
    for(int i = A.size() - 1;i >= 0;i --)
    {  
// 否则就要从最高位开始看(因为执行这个函数前,A和B数组都已经倒序,所以这里要从后往前看)
        if(A[i] != B[i]) return A[i] > B[i];
        // 如果A的当前位和B的当前位不相等,当前位大的更大
    }
    return true; // 如果A、B数组都相等,这里可以直接返回true,当然也可以直接输出0
}
vector <int> sub(vector <int> &A,vector <int> &B)
{ 	// A - B

    int t = 0;                // 每一位上相减得到的数
    vector <int> C;           // 最后的答案
// 遍历一遍,和高精度加法不一样的是,只要遍历完A就行了,因为这里A肯定比B长
    for(int i = 0;i < A.size();i ++)
    { 
        t = A[i] - t;// t要等于A的当前位减掉自己,因为上一位有可能出现借位的情况
		if(i < B.size()) t -= B[i];  // 如果没有遍历完B,那么t减掉B的当前位
		 C.push_back((t + 10) % 10); 
        
        // 更新C数组
        // 这里如果没有借位,(t + 10) % 10就刚好等于t
        // 如果这里有借位,(t + 10) % 10就会借一个10下来
        
        if(t < 0) t = 1; 
 // 如果t < 0,说明不够减,需要借位,把t赋值为1,就是在下一次执行中,A的当前位会减掉t
        else t = 0;      // 否则够减,赋值为0,不用借位
    }
    while(C.size() > 1 && C.back() == 0) C.pop_back(); // 删除前导0
    return C; // 返回答案
}
int main(){
    string a,b;	   // 两个数,因为很大,所以用string来存
    cin>>a>>b; 		// 读入
    vector <int> A,B;   // 两个数,因为减法是从最低位开始减,我们可以把两个数倒过来
    for(int i = a.size() - 1;i >= 0;i --) A.push_back(a[i] - '0');
    // 把a数组到过来存入A,记得a是string类型的数组,要减去'0'让它变成数字
    for(int i = b.size() - 1;i >= 0;i --) B.push_back(b[i] - '0'); 
    // 把b数组倒过来存入B
    if(cmp(A,B))
    { 
        // 如果A > B
        auto C = sub(A,B); // 那么可以直接相减
        for(int i = C.size() - 1;i >= 0;i --) printf("%d",C[i]); 
        // 最后因为C是倒着的,需要反向输出
    }
    else
    {   // 否则A < B,需要计算-(B - A)
        auto C = sub(B,A); // 计算B - A
        printf("-"); // 给前面加上一个负号
        for(int i = C.size() - 1;i >= 0;i --) printf("%d",C[i]); // 反向输出C数组
    }
    return 0;
}

✨四、高精度乘法

高精度乘法就没什么好说的,直接上习题,代码有讲解

💖1、题目 Acwing 793. 高精度乘法

给定两个非负整数(不含前导 0)A和 B,请你计算 A×B 的值。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共一行,包含 A×B 的值。

数据范围

1≤A的长度≤100000
0≤B≤100000

输入样例:
2
3
输出样例:
6

2、代码展示

#include<iostream>
#include<string>
#include<vector>
using namespace std;
vector<int> mul(vector<int>&A,int b)
{
    vector<int> C;
    int t=0;//进位
    //A的长度一定比b长,而且这里加了`||t`
    for(int i=0;i<A.size()||t;i++)
    {
        if(i<A.size()) t+=A[i]*b;
        C.push_back(t%10);
        t/=10;
    }
    //去除前导0
    while(C.size()>1&&C.back()==0) C.pop_back();
    return C;
}
int main()
{
    string a;
    int b;
    cin>>a>>b;
    vector<int> A;
    //倒序
    for(int i=a.size()-1;i>=0;i--) A.push_back(a[i]-'0');
    auto C=mul(A,b);
    for(int i=C.size()-1;i>=0;i--) cout<<C[i];
    return 0;
}

✨五、高精度除法

1、模拟与算法

我们先模拟一下

需要注意的就两点第一个:余数r传入函数的时候一定要传入引用,因为要修改并返回r的值

第二个:上一位的余数乘以10,再加上当前位上的数就是余数

💖2、题目 Acwing 794. 高精度除法

给定两个非负整数(不含前导 00) A,B,请你计算 A/B的商和余数。

输入格式

共两行,第一行包含整数 A,第二行包含整数 B。

输出格式

共两行,第一行输出所求的商,第二行输出所求余数。

数据范围

1≤A的长度≤100000
1≤B≤10000
B不一定不为 0

输入样例:
7
2
输出样例:
3
1

3、代码展示

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector <int> div(vector <int> &A,int b,int &r)
{ 
    // 取r的地址符,是为了更改r的值,方便后面输出余数
    vector <int> C; // 答案
    r = 0; // 余数
    for(int i = A.size() - 1;i >= 0;i --)
    { 
        // 从最高位开始处理
        r = r * 10 + A[i]; // 上一次的余数乘10,再加上当前位上的数,就是被除数
        C.push_back(r / b); // 往C里压入这个被除数除b
        r %= b; // 计算余数
    }
    reverse(C.begin(),C.end()); 
    // 因为除法运算中从高位开始计算,而前导0都在顶部而不是底部,所以要翻转过来
    while (C.size() > 1 && C.back() == 0) C.pop_back(); // 去除前导0
    return C; // 返回答案
}
int main()
{
    string a;
    int b;
    cin>>a>>b;
    vector <int> A;
    for(int i = a.size() - 1;i >= 0;i --) A.push_back(a[i] - '0'); // 倒序
    int r;
    auto C = div(A,b,r); // 答案
    for(int i = C.size() - 1;i >= 0;i --) cout<<C[i];
    cout<<endl<<r<<endl;
    return 0;
}

有关算法笔记——高精度算法(附源码)的更多相关文章

  1. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  2. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  3. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  4. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  5. ruby-on-rails - ruby on rails 模型验证中的浮点精度 - 2

    我正在尝试使用正则表达式验证美元金额:^[0-9]+\.[0-9]{2}$这工作正常,但每当用户提交表单并且美元金额以0(零)结尾时,ruby(或rails?)将0砍掉。所以500.00变成500.0,因此正则表达式验证失败。有没有办法让ruby​​/rails保持用户输入的格式,而不管尾随零? 最佳答案 我假设您的美元金额是小数类型。因此,用户在字段中输入的任何值在保存到数据库之前都会从字符串转换为适当的类型。验证适用于已转换为数字类型的值,因此在您的情况下,正则表达式并不是真正合适的验证过滤器。不过,您有几种可能性可以解决这个问

  6. 100个python算法超详细讲解:画直线 - 2

    1.问题描述使用Python的turtle(海龟绘图)模块提供的函数绘制直线。2.问题分析一幅复杂的图形通常都可以由点、直线、三角形、矩形、平行四边形、圆、椭圆和圆弧等基本图形组成。其中的三角形、矩形、平行四边形又可以由直线组成,而直线又是由两个点确定的。我们使用Python的turtle模块所提供的函数来绘制直线。在使用之前我们先介绍一下turtle模块的相关知识点。turtle模块提供面向对象和面向过程两种形式的海龟绘图基本组件。面向对象的接口类如下:1)TurtleScreen类:定义图形窗口作为绘图海龟的运动场。它的构造器需要一个tkinter.Canvas或ScrolledCanva

  7. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  8. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  9. (附源码)vue3.0+.NET6实现聊天室(实时聊天SignalR) - 2

    参考文章搭建文章gitte源码在线体验可以注册两个号来测试演示图:一.整体介绍  介绍SignalR一种通讯模型Hub(中心模型,或者叫集线器模型),调用这个模型写好的方法,去发送消息。  内容有:    ①:Hub模型的方法介绍    ②:服务器端代码介绍    ③:前端vue3安装并调用后端方法    ④:聊天室样例整体流程:1、进入网站->调用连接SignalR的方法2、与好友发送消息->调用SignalR的自定义方法 前端通过,signalR内置方法.invoke()  去请求接口3、监听接受方法(渲染消息)通过new signalR.HubConnectionBuilder().on

  10. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

随机推荐