当前位置: 首页 > news >正文

算法-----高精度算法1(高精度加法,高精度减法)(详解)

什么是高精度算法?

高精度的意思就是他得名字----高的精度,简单说就是位数很大,而高精度算法就是将这些高精度数(位数很大在几百几千几万位的数叫高精度数)通过计算机的型式模拟出来结果。

为什么要用高精度算法?

在这里插入图片描述

我们都知道c++中int的最大值是2^31,unsigned int的最大值是2的32次方,最大的unsigned long long可以到18446744073709551615 。double是浮点型的最大类型,他的最大值是1.7 * 10^308。
这些数据类型对于1+1=2或43545*51345=2235818025这些式子来说绰绰有余,但如果是下面的呢----
153169256934561745635416456903465967693845681963457348+13547477864672672675474676754676783587875372274=? 265464562574318759893457913479346x6524632656224562664=?
3466779657942964574257456/432654724567=?..?
这些式子的数和结果都非常大long long 和 double 都存不下,这时就是要用高精度来计算了

高精度加法

1168:大整数加法
P1601 A+B Problem(高精)
因为不能用计算机直接计算,只能靠模拟。
让我们回顾一下小学一年级时学的加法。

在这里插入图片描述
通过这个竖式我们想想是否可以把高精度加法转换成一道让我们模拟加法竖式的模拟题呢?答案是肯定的
带着这个假想我们可以尝试下
首先初始化
注意!!!:因为位数较大所以我们要用字符串或字符数组

const int N=205;    //定义大小 
string s1,s2;    //俩数 
int a[N],b[N],c[N];   //存放俩数及结果数组 

好了第二步-------读入(read)

void read(){cin>>s1>>s2;
} 

好读入结束,等下,这么草草就结束了a,b数组怎么办。
所以为了照顾a,b数组,我们需要把俩字符串数转成整数数组的型式。
但真的是顺着存储吗?不对
如果顺着存储就是这样
在这里插入图片描述
本来1257+934的式子竟然变了!而且当你好不容易把他变回去时就会发现如果进位时如123+930数组下标竟然需要负数才能存下那个进位的1了!所以顺着存不行,那试试逆序存呢?
大家可以在草稿纸上试试可以发现,逆着存是可以的,也防止了进位溢出的情况
所以,对于存储s1,s2俩数,应用整数数组逆着存。

void read(){cin>>s1>>s2;int len1=s1.size(),len2=s2.size();for(int i=0;i<len1;i++) a[i]=(s1[len1-i-1]-'0');  //逆序存储。需要字符转整数for(int j=0;j<len2;j++) b[j]=(s2[len2-j-1]-'0');
} 

好的终于到模拟部分了
让我们先考虑一下重点
1.考虑进位
2.考虑该进位多少
3.最重要的一点。前导零该怎么办
4.最高位进位
好的一步步来
第一点。因为单个位最大是9,俩9相加才18,进位不可能超1,所以第一部分和第二部分可以同时考虑。如果结果大于10,我们可以将结果-10,或直接不判断直接%10,当然我们也要考虑到当前的i+1位也要+1,所以我们可以用变量来表示这种情况。第三点我们可以从尾开始遍历碰到0就舍去(len-1).如果没碰到就break。第四点我们可以用变量储存模拟完毕后特判下
好分析完毕,代码如下

void count(){int jw=0;len=max(s1.size(),s2.size());   //c的长度是俩数中的最大值或+1for(int i=0;i<len;i++){c[i]=a[i]+b[i]+jw;    //求当前结果jw=c[i]/10;        //进位数c[i]%=10;    //得出当前数} if(jw==1){   //处理最高位进位len++;c[len-1]=1;}while(c[len-1]==0) len--;    //去前导零
}

等下考虑下0+0的结果 ,是空,不是0吗,原来当len==1时就算是0也不能舍去
修改如下

void count(){int jw=0;len=max(s1.size(),s2.size());for(int i=0;i<len;i++){c[i]=a[i]+b[i]+jw;jw=c[i]/10;c[i]%=10;} if(jw==1){len++;c[len-1]=1;}while(len>1&&c[len-1]==0) len--;
}

最后到输出部分了,应为开始时是逆序存所以也要逆序输出正所谓负负得正

void print(){for(int i=len-1;i>=0;i--) cout<<c[i];
}

最后总代如下

#include<bits/stdc++.h>
using namespace std;
const int N=205;     
string s1,s2;  
int a[N],b[N],c[N];  
int len;
void read(){ //读入cin>>s1>>s2;int len1=s1.size(),len2=s2.size();for(int i=0;i<len1;i++) a[i]=(s1[len1-i-1]-'0');for(int j=0;j<len2;j++) b[j]=(s2[len2-j-1]-'0');
} 
void count(){    //模拟竖式int jw=0;len=max(s1.size(),s2.size());for(int i=0;i<len;i++){c[i]=a[i]+b[i]+jw;jw=c[i]/10;c[i]%=10;} if(jw==1){len++;c[len-1]=1;}while(len>1&&c[len-1]==0) len--;
}
void print(){  //输出for(int i=len-1;i>=0;i--) cout<<c[i];
}
int main(){
read();
count();
print();return 0;
}

另外用结构体来计算大整数加法也是常见的,这里不做多说明了与上文类似

#include<bits/stdc++.h>
using namespace std;
string str;
struct node{   //定义int len,s[205];node(){len=0;memset(s,0,sizeof(s));}
};
node a,b,c;
node operator + (const node&a,const node&b){  //重载加法运算符node c;c.len=max(a.len,b.len);for(int i=1;i<=c.len;i++){c.s[i]+=a.s[i]+b.s[i];c.s[i+1]+=c.s[i]/10;c.s[i]%=10;}if(c.s[c.len+1]) c.len++;return c;
}
node read(){   //读入加去前导零cin>>str;int len=str.size();node a;a.len=len;for(int i=0;i<len;i++){a.s[len-i]=str[i]-'0';}while(a.len>1&&a.s[a.len]==0) a.len--;return a;
}void print(node a){//输出for(int i=a.len;i>=1;i--) cout<<a.s[i];
}
int main(){a=read(),b=read();
c=a+b;
print(c);return 0;
}

高精度减法

1169:大整数减法
与高精度加法类似也是模拟
初始化+读入

string s1,s2;
int a[205],b[205],c[205];
int len;
void read(){cin>>s1>>s2;int n=s1.size(),m=s2.size();len=max(n,m);for(int i=0;i<n;i++){a[i]=s1[n-i-1]-'0';}for(int j=0;j<m;j++){b[j]=s2[m-j-1]-'0';}
}

模拟竖式。
这里也有两项需考虑
1.借位
2.去前导零
第二步相信你们很轻松就能解决。而第一步也很简单我们正常减,如果c[i]<0,那么需要借位了有加就有减,所以c[i]+=10;c[i+1]–;
代码如下

void less(){for(int i=0;i<len;i++){c[i]+=a[i]-b[i];if(c[i]<0){c[i]+=10;c[i+1]--;}}while(len>1&&c[len-1]==0) len--;
}

最后逆序输出

void print(){for(int i=len-1;i>=0;i--) cout<<c[i];
}

总代码

#include<bits/stdc++.h>
using namespace std;
string s1,s2;
int a[205],b[205],c[205];
int len;
void read(){cin>>s1>>s2;int n=s1.size(),m=s2.size();len=max(n,m);for(int i=0;i<n;i++){a[i]=s1[n-i-1]-'0';}for(int j=0;j<m;j++){b[j]=s2[m-j-1]-'0';}
}
void lss(){for(int i=0;i<len;i++){c[i]+=a[i]-b[i];if(c[i]<0){c[i]+=10;c[i+1]--;}}while(len>1&&c[len-1]==0) len--;
}
void print(){for(int i=len-1;i>=0;i--) cout<<c[i];
}
int main(){
read();
lss();
print();return 0;
}

这边结构体减法代码就不放了,有兴趣可以自己做下。
总结下来,只要会高精度加法就会高精度减法。

未完待续。。。。。。

相关文章:

  • 掘根宝典之C++运算符重载
  • Android Graphics 图像显示系统 - 开篇
  • ECMAScript Modules 规范示例详解
  • vue三种路由守卫详解
  • JDK、JRE、JVM三者关系详解
  • 当go get获取不到软件包时
  • 第六篇:MySQL图形化管理工具
  • 关于在分布式环境中RVN和使用场景的介绍3
  • Kafka集群安装与部署
  • 力扣-1. 两数之和
  • 华为问界M9:领跑未来智能交通的自动驾驶黑科技
  • ACK One Argo工作流:实现动态 Fan-out/Fan-in 任务编排
  • TinUI v5预发布记录
  • Javaweb之SpringBootWeb案例之propagation属性案例演示的详细解析
  • 使用C++从零开始,自己写一个MiniWeb
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • ComponentOne 2017 V2版本正式发布
  • conda常用的命令
  • Date型的使用
  • JavaScript 一些 DOM 的知识点
  • Javascript设计模式学习之Observer(观察者)模式
  • mongo索引构建
  • mysql常用命令汇总
  • Octave 入门
  • Redis 中的布隆过滤器
  • Spark RDD学习: aggregate函数
  • SQLServer之创建数据库快照
  • Vue全家桶实现一个Web App
  • Web设计流程优化:网页效果图设计新思路
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 对超线程几个不同角度的解释
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • - 概述 - 《设计模式(极简c++版)》
  • 经典排序算法及其 Java 实现
  • 每天10道Java面试题,跟我走,offer有!
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 深度学习中的信息论知识详解
  • 智能合约开发环境搭建及Hello World合约
  • No resource identifier found for attribute,RxJava之zip操作符
  • ​​​​​​​GitLab 之 GitLab-Runner 安装,配置与问题汇总
  • ​Linux Ubuntu环境下使用docker构建spark运行环境(超级详细)
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • .NET Core跨平台微服务学习资源
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .Net Winform开发笔记(一)
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET/C# 的字符串暂存池
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • .NET运行机制
  • @RequestParam,@RequestBody和@PathVariable 区别
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [acm算法学习] 后缀数组SA
  • [acwing周赛复盘] 第 69 场周赛20220917