【算法】高精度算法:加减乘除(全)

2023-11-04

看的视频在这里。
题目:
加法
减法
乘法
除法:高/低

加法

思想:用数组模拟高精度。
在这里插入图片描述

算法核心:

c[i]+=a[i]+b[i];
c[i+1]=c[i]/10;
c[i]=c[i]%10;

注意:是c[i]+=a[i]+b[i],是累加

例题:求a+b, a、b范围都<=10^500;

注意:
1、将字符串转成数组模拟大数时要将字符转置,这样才方便做加法,因为数学是向右对齐做加法的,而数组是从左到右的。如:
1234+789==1234+0789 对齐相加,而不是1234+7890对齐相加。
转置即向右对齐,这样进位就向左(向小的位置)进位。

2、la-i最大是la,最小是1.故后面的核心算法是从1开始到lc;

代码如下(有注释):

#include<bits/stdc++.h>
using namespace std;
char s1[505],s2[505];
int a[505],b[505],c[505];
int main()
{
	//用数组模拟高精度算法
	
	int la,lb,lc;
	cin>>s1>>s2;
		
	//得知长度 
	la=strlen(s1);
	lb=strlen(s2);
	
	//将字符转为数字,并将字符转置便于计算
	//此时数字是倒过来的,因为数字的加法是从低位向高位相加(向右对齐) 
	for(int i=0;i<la;i++)
	{
		a[la-i]=s1[i]-'0';
	 } 
	 
	for(int i=0;i<lb;i++)
	{
		b[lb-i]=s2[i]-'0';
	}
	
	//最高位数 
	lc=max(la,lb)+1;
	
	//核心步骤 
	for(int i=1;i<=lc;i++) //为什么从1开始?因为上面的la-i最小就是1 
	{
		c[i]+=a[i]+b[i];
		c[i+1]=c[i]/10;
		c[i]=c[i]%10;
	}
	
	//删除前导0 
	if(c[lc]==0&&lc>0) lc--;
	
	for(int i=lc;i>0;i--)
	{
		cout<<c[i];
	}
	
	return 0;
}

减法

算法核心:
1、若a<b,则交换a与b,并在结果处加上负号。

2、如果a[i]<b[i],则需要高位借位。
核心代码:

if(a[i]<b[i])
{
	a[i+1]--;
	a[i]=a[i]+10;
}
c[i]=a[i]-b[i];

高精度减法例题的代码:

#include<bits/stdc++.h>
using namespace std;

bool compare(char s1[],char s2[])//如果s1>=s2,返回true,否则false; 
{
	int u=strlen(s1),v=strlen(s2);
	if(u>v) return true;
	
	if(u!=v) return u>v; //若u>v,则返回了1,否则0,符合题意
	
	//判断u==v的情况 
	for(int i=0;i<u;i++)
	{
		if(s1[i]!=s2[i])   return s1[i]>s2[i];//这里比较的是从第一位开始的数字; 
	} 
	
	//若还能到这里,则两数相等
	return 1; 
}

char s1[100000],s2[100000];
int a[100000],b[100000],c[100000];
int main()
{
	int la,lb,lc,flag=0;
	cin>>s1>>s2;
	
	if(!compare(s1,s2))//若s1<s2,则flag=1,交换两数字
	{
		flag=1;
		char s3[10000];
		strcpy(s3,s1);
		strcpy(s1,s2);
		strcpy(s2,s3);
	 } 
	 
	 //到这里s1>=s2了
	
	la=strlen(s1);
	lb=strlen(s2);
	
	//转化数字并转置,因减法要向右对齐,而转置后向左对齐,正是数组从左到右的顺序 
	for(int i=0;i<la;i++)
	{
		a[la-i]=s1[i]-'0';
	} 
	 
	for(int i=0;i<lb;i++)
	{
		b[lb-i]=s2[i]-'0';
	}
	
	lc=max(la,lb);//做减法不会进位,不必加1
	
	//由上面的减法可知,数组最小从1开始 
	for(int i=1;i<=lc;i++)
	{
		if(a[i]<b[i])
		{
			a[i+1]--;
			a[i]=a[i]+10;
		}
		c[i]=a[i]-b[i];
	}
	
	//删去前导零,因为减法可能有很多零,要用循环 
	while(c[lc]==0&&lc>1)
	{
		lc--;
	}
	
	if(flag==1)  cout<<"-";
	
	//反着输出回来 
	for(int i=lc;i>0;i--)
	{
		cout<<c[i];
	}
	return 0;
}

减法跟加法有许多相似之处。

乘法

一个例子:
在这里插入图片描述
核心算法:

c[i+j-1]=c[i+j-1]+a[i]*b[j];
c[i+j]=c[i+j]+c[i+j-1]/10;
c[i+j-1]=c[i+j-1]%10;

注意,乘法的最大位数是两个乘数之和
但是!
若是有一个乘数是0,则用if删去前导零会有很多0,如:

0*99999999999999=0000000000000

所以还是要用while删除前导0,或者特判

代码如下:

#include<bits/stdc++.h>
using namespace std;
char s1[10000],s2[10000];
int a[10000],b[10000],c[10000];
int main()
{
	int la,lb,lc;
	cin>>s1>>s2;
	
	la=strlen(s1);
	lb=strlen(s2);
	
	for(int i=0;i<la;i++)
	{
		a[la-i]=s1[i]-'0';
	}
	for(int i=0;i<lb;i++)
	{
		b[lb-i]=s2[i]-'0';
	}
	
	//乘法的位数 
	lc=la+lb;
	
	//核心算法
	for(int i=1;i<=la;i++)
	{
		for(int j=1;j<=lb;j++)
		{
			c[i+j-1]+=a[i]*b[j];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]%=10;
		}
	 } 
	 
	//本来lc最多只会比答案多1位,用if删去前导0即可
	//但是!要注意,若有一个乘数是0,则会有很多0,则用while稳妥 
	while(c[lc]==0&&lc>1) lc--; 
	for(int i=lc;i>0;i--)
	{
		cout<<c[i];
	}
	
	return 0;
}

重点是找到a[i] b[i]和c[i] 的规律。

除法

高精度除以低精度

例子:
在这里插入图片描述

核心代码:

	for(int i=1;i<=la;i++)
	{
		c[i]=(x*10+a[i])/b;
		x=(x*10+a[i])%b;
	 } 

注意:这里删除前导零的方法是:
若前面有0,lc就加1,输出的时候从lc开始,这样就把前导零跳过了。

整体代码:

#include<bits/stdc++.h>
using namespace std;

char s1[5005];
long long int b,c[5005],x,a[5005],la,lc;
int main()
{
	cin>>s1>>b;
	
	la=strlen(s1);
	
	//将被除数放入数组 
	for(int i=1;i<=la;i++)
	{
		a[i]=s1[i-1]-'0';
	}
	
	//核心算法
	for(int i=1;i<=la;i++)
	{
		c[i]=(x*10+a[i])/b;
		x=(x*10+a[i])%b;
	 } 
	 
	lc=1;
	while(c[lc]==0&&lc<la) lc++;//删除前导零 
	for(int i=lc;i<=la;i++)
	{
		cout<<c[i];
	}
	
	return 0;
}

高精度除以高精度

例子:
在这里插入图片描述

除数是高精度不能逐位试商,因为可能很多都试不出来。故用减法模拟除法

注意:
1、答案的位数lc=la-lb+1;
如,20/4=5,lc是2(左边第一个是1噢)。
2、最高位的商的来源:用高精度减法,能减多少次商就是几。
3、后面位数的商:被除数是把前面余数*10加上后一位,用高精度减法,重复注意2的步骤。

一个例子:531518/123,第3位的商应该是这样求:
531518-123000,可以减几次,该位数就是几。即,除数左移3位,使得被除数与除数位数相同。
减完之后的39518/123,就是39518-12300能进行几次,即,除数左移两位。

此代码会有很多函数,反正就是让我自己写也写不出来…

代码:

#include<bits/stdc++.h>
using namespace std;

char s1[5005],s2[5005];
int a[305],b[305],c[305],tmp[305];//   a/b==c

//输入字符串并将其转置,变成数字的函数 
void init(int *x)
{
	char s[305];
	cin>>s;
	x[0]=strlen(s);
	
	//将字符串倒序转换为数字:因为涉及到了减法 
	for(int i=0;i<x[0];i++)
	{
		x[x[0]-i]=s[i]-'0';
	}
}


//将除数与被除数对齐,用于做减法的函数:如将123变成12300 
void numcpy(int p[],int q[],int n)
{
	for(int i=1;i<=p[0];i++)
	{
		q[i+n-1]=p[i];//将数字往后推,前面就是0了,转过来就是对齐了的123000(例子) 
	}
	q[0]=p[0]+n-1;
}

 
 //比较两个数谁大的函数
 int compare(int a[],int b[])//返回1:a>b;0:a==b;-1:a<b 
 {
 	if(a[0]>b[0])  return 1;
 	if(a[0]<b[0])  return -1;
 	
 	//走到这里就是位数一样,再往前一位一位地比较 
 	for(int i=a[0];i>0;i--)
 	{
 		if(a[i]>b[i])  return 1;
 		if(a[i]<b[i])  return -1;
	 }
	 
	//a==b
	return 0;
  }
  


//相减的函数
void minu(int a[],int b[])
{
	for(int i=1;i<=a[0];i++)
	{
		if(a[i]<b[i])
		{
			a[i+1]--;
			a[i]=a[i]+10;
		}
		//a[i]是结果了 
		a[i]=a[i]-b[i];
		while(a[a[0]]==0&&a[0]>0)  a[0]--;
	}
 } 

//输出答案函数:转置 
void print(int a[])
{
	if(a[0]==0)
	{
		cout<<0;
		return;
	}
	
	for(int i=a[0];i>=1;i--)
	{
		cout<<a[i];
	}
	return;
 } 
 
 
int main()
{	
	init(a);
	init(b);
	
	//因为数组都是从1开始存的,故a[0]等是没有用的,故将数字的位数存入a[0]
	//作用是:控制商的位数 
	c[0]=a[0]-b[0]+1;
		
	//核心代码: 
	for(int i=c[0];i>=1;i--)
	{
		memset(tmp,0,sizeof(tmp));
		numcpy(b,tmp,i);
		
		//以减法做除法的核心代码
		while(compare(a,tmp)>=0)
		{
			c[i]++;
			minu(a,tmp);
		}
		 
	}
	
	//删去前导零
	while(c[c[0]]==0&&c[0]>0)  c[0]--;
	
	
	//输出商 
	print(c);
	cout<<endl;
	//输出余数(a剩下的除不了的就是余数~) 
	print(a); 
	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【算法】高精度算法:加减乘除(全) 的相关文章

随机推荐

  • python numpy从坐标序列中计算累计移动距离

    也是从其他程序中学习得到计算距离 position 通过list来存储坐标xy position append x y position np array position 转换成数组 dist arr np concatenate np
  • 基于docker一行命令搭建个人博客wordPress

    前言 作为对技术热爱的一群小伙伴们 技术分享开源社区的贡献都是我们技术人引以为傲的一件事情 不仅如此 技术分享或者记录也是对自己职业成长的记录 更甚者 如果你的技术分享深度不错 并且帮助到别人那么在面试中也是又很大帮助的 今天就给大家谈一下
  • 两条轨迹相似度算法,轨迹相似性度量

    百度地图 百度地图是百度提供的一项网络地图搜索服务 覆盖了国内近400个城市 数千个区县 在百度地图里 用户可以查询街道 商场 楼盘的地理位置 也可以找到离您最近的所有餐馆 学校 银行 公园等等 2010年8月26日 在使用百度地图服务时
  • VS2019环境下C++配置环境/创建动态链接库

    文章目录 前言 一 配置环境 0 准备 1 添加项目表 2 include文件与lib文件的配置 include文件设置 lib文件配置 二 使用已有代码生成动态链接库 前言 最近有一个收尾的项目分到了手里 由于基本没有使用过VS2019所
  • linux内核oops错误码说明,Linux Kernel Oops异常分析

    0 linux内核异常常用分析方法 异常地址是否在0附近 确认是否是空指针解引用问题 异常地址是否在iomem映射区 确认是否是设备访问总线异常问题 如PCI异常导致的地址访问异常 异常地址是否在stack附近 如果相邻 要考虑是否被踩 比
  • 验证尼科彻斯定理

    验证尼科彻斯定理 即 任何一个整数的立方都可以写成一串连续奇数的和 问题分析与算法设计 本题是一个定理 我们先来证明它是成立的 对于任一正整数a 不论a是奇数还是偶数 整数 a a a 1 必然为奇数 构造一个等差数列 数列的首项为 a a
  • SVN迁移至GIT,并附带历史提交记录

    文章目录 SVN代码同步至GIT 背景 准备工作 操作步骤 SVN代码同步至GIT 背景 近年随着信息工程的多元化发展 GIT逐渐取代SVN成为主流的版本管理工具 部门的项目代码也决定迁移至git进行管理 所以就调研了一下具体的实现方案 要
  • linux创建git仓库

    1 安装 yum install y git 2 查看 Git 版本 git version 3 查看有没有git用户 id git 没有用户创建 useradd git 设置密码 passwd git 删除密码 passwd d f gi
  • Tomcat配置远程调试端口

    1 Linxu系统 bin startup sh开始处中增加如下内容 Java代码 declare x CATALINA OPTS server Xdebug Xnoagent Djava compiler NONE Xrunjdwp tr
  • JVM系列-第10章-垃圾回收概述和相关算法

    文章目录 toc 垃圾回收概述 大厂面试题 蚂蚁金服 百度 天猫 滴滴 京东 阿里 字节跳动 什么是垃圾 为什么需要GC 早期垃圾回收 Java 垃圾回收机制 自动内存管理 应该关心哪些区域的回收 垃圾回收相关算法 标记阶段 引用计数算法
  • Python实现选择排序

    选择排序简介 选择排序 Selection sort 是一种简单直观的排序算法 简单来说就是从无序队列里面挑选最小的元素 和无序队列头部元素替换 放到有序队列中 最终全部元素形成一个有序的队列 选择排序原理 首先在未排序序列中找到最小 大
  • tomcat的启动流程及原理

    组件介绍 Tomcat 最重要的是两个组件是 Connector 连接器 和 Container 容器 集装箱 Connector 组件是可以被替换 这样可以提供给服务器设计者更多的选择 因为这个组件是如此重要 不仅跟服务器的设计的本身 而
  • 当我遵循了这 16 条规范写代码,同事只对我说了三个字: 666

    作者 涛姐涛哥 链接 cnblogs com taojietaoge p 11575376 html 如何更规范化编写Java 代码 Many of the happiest people are those who own the lea
  • CTFshow 信息收集 web18

    根据提示 不要着急 休息 休息一会儿 玩101分给你flag 打开是一个小游戏 要么玩到101分 要么直接作弊 查看源代码 发现js文件 里面发现有个score 0 只要它为101就应该能得到flag了吧 ctrl F搜索score在最底下
  • vue 报错error: 'ev' is defined but never used (no-unused-vars)

    我要做的是用vue在网页上显示一个button 报错信息 修改 没有在components中调用
  • MyBatis-plus 提示 Data truncation: Out of range value for column ‘id‘ at row 1

    记录一下MyBatis plus 提示的错误信息 Error updating database Cause com mysql cj jdbc exceptions MysqlDataTruncation Data truncation
  • Tcpdump命令详解

    目录 一 tcpdump作用 二 tcpdump命令选项和捕获主机到主机的数据包 2 1 命令选项 2 2 tcpdump表达式 关于数据类型的关键字 数据传输方向的关键字 协议关键字 其他关键字 2 3 tcpdump捕获方式 编辑 一
  • 概率论与数理统计 (二)计算题和应用题

    概率论一些知识 https blog csdn net zuoyonggang123 article details 79110916 utm medium distribute pc relevant none task blog OPE
  • 写函数,判断用户传入的参数(字符串、列表、元组)长度是否大于5

    def estimateLength data if len data gt 5 print 该参数长度大于5 else print 该参数长度不大于5 str xiao ran list 12 34 56 78 90 tuple 小灰灰
  • 【算法】高精度算法:加减乘除(全)

    看的视频在这里 题目 加法 减法 乘法 除法 高 低 加法 思想 用数组模拟高精度 算法核心 c i a i b i c i 1 c i 10 c i c i 10 注意 是c i a i b i 是累加 例题 求a b a b范围都 lt