大数运算(加减乘除和输入、输出模块)

      为什么会有大数呢?因为long long通常为64位范围约为 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807,最多也就19位,那么超过19位的如何计算呢?这就引申出来大数了。

        本博客适合思考过这道题,但是没做出来或感觉代码不够简洁的朋友来看。


  简述   

          通过这道题,我加深了对数据处理的重要性以及模块化编程的重要性,虽然没有用到高级的算法,但是给我带来了好多新的想法。

        加减乘除运算为人类发明的,那么这道题自然要用人类的思路来解这道题,我们小学便以及学过,故我们只需要将小学的做题思维转化为我们的高级语言就行了。简单点来说就是模拟我们运算加减乘除的过程。

        总代码不超过一百行,但如果我们的数据处理不好,和不以一个小学生的思维去做这道题,那二百行都不一定写得完。我之前的写法便是没有以一个正常人的思维去思考,昨天问了老师这道题,才理清问题。

  •         加法运算:两个数从低位到高位依次相加,大于10进位。
  •         减法运算:两个数从低位到高位依次相加,大于10补位。
  •         乘法运算:乘数的从低位到高位每一位都乘以被乘数,大于10进位。
  •         除法运算:从被除数的最高位开始,减去商的一位乘以除数,将余数补位。

        首先要考虑的便是数据存储的问题。输入30位整数:

100000000000000000000000000030

        从左到右依次减小,超过19为位肯定要用数组存了,那么用什么类型呢,这里每一个地址存储一个个位数,那么就不超过4个bit,其实用半个bits就行了,我们这里就用1个bist的char类型来存储。这里我们假设所有输入的数字不超过50位(范围很重要,范围一旦确定,这道题就会简单很多了)。

        我们定义大数类型:

#define N 50
typedef char BIG_NUM[N];//存储大数

输入/输出模块

        运算无非就是进位和补位,那么怎么才能进位和补位方便呢?我们的输入输出方式要使得进位和补位方便,现在我展示两种方法:

  • 靠右存储:高位补零 ,去除补零外,从左到右依次减小。

  • 靠左存储:低位补零,去除补零外,从左到右依次减小。

        我们既要保证进位补位方便还要保证输入输出方便。假设我们用靠左存储存储,如果计算998+2=1000的话,那么得到的结果就需要手动进位,并且我们还要计算位数。

        如果用靠右存储的话,左边高位补0,因为0+0=0,0*0=0,0/0=0,0-0=0,故我们不需要考虑进位问题,因为只要位数不超过50,那么高位的0再需要进位时更改就行了,至于位数问题,那就只需再输出时去掉高位的零就行了。

        故我们就已经确定了输入输出模块的内容了。

        输入的时候因为是从高到低输入,不知道具体多少位,所以我们需要先靠左存储,然后移位到右边。

        输出时从左到右(高位到低位)依次输出,可以选择是否输出高位0。

输入

void input(BIG_NUM x)
{int i, j;for(i=0; i<N && isdigit(x[i]=getchar()); ++i) x[i] -= '0';//i(从0开始)为大数加上'\n'的个数for(--i, j=N-1;i>=0;--i,--j) x[j] = x[i];//移位至靠右存储先执行一个i--,是因为现在的x[i]是'\n'for(;j>=0;--j) x[j] = 0;//前面补0
}

输出

void output(BIG_NUM x)
{int i;for(i=0; i<N-1 && x[i]==0; ++i);//i<N-1因为要保证结果为0的情况for(; i<N; ++i) putchar('0'+x[i]);
}

加法 

int add(BIG_NUM x, BIG_NUM y, BIG_NUM z) /* z = x + y */
{int i, carry;for(i=N-1, carry=0; i>=0; --i){int s = x[i] + y[i] + carry;z[i] = s % 10;carry = s / 10;}return carry;
}

         这里如果返回的carry不为0就代表得到的结果大于五十位,可以在根据实际情况进行改进。

减法 

int sub(BIG_NUM x, BIG_NUM y, BIG_NUM z) /* z = x - y */
{int i, carry;for(i=N-1, carry=0; i>=0; --i){int s = x[i] - y[i] - carry;if( s < 0) {carry = 1; s = 10 + s;} else carry = 0;z[i] = s;}return carry;
}

         carry返回为1就代表相减的两个数,第一个小于第二个。

 乘法

int mul(BIG_NUM x, BIG_NUM y, BIG_NUM z) /* z = x * y */
{int i, j, carry;char t[N+N];memset(t, 0, N+N);for(j=N-1; j>=0; --j)for(i=N-1, carry=0; i>=0; --i){int s = t[i+j+1] + x[i] * y[j] + carry;t[i+j+1] = s % 10;carry = s / 10;}t[0] = carry;for(i=0; i<N; ++i) z[i] = t[i+N];for(i=0, carry=0; i<N; ++i) carry |= t[i];//判断是否超过50return carry;
}

         这里如果返回的carry不为0就代表得到的结果大于五十位,可以在根据实际情况进行改进。其中t是100位,可以适当调整。

除法

        除法部分稍微复杂,但还是模拟小学做题,每一位商的值就是1-9,和我们算除法一样,这一点用到逆向思维,这九种情况我们需要一个一个来试试。比如108/9=n,换成n*9=108,n的值为1-9一个一个试,如果n为9还是不够,那么剩下的就是余数,下一位就需要减少余数*10。

        我们这里做一个例子模仿一下代码的运算。如1080/9,先判断1-n*9,当n为0时,余数1,当n为1时,余数为负,故这一位的商为0,余数为1;

        再判断 1*10+0-n*9,这里的n为1,依次类推便能得到结果为120.

        代码如下:

void seti(BIG_NUM x, unsigned int u){ /* y = u */int i, s;for(i=N-1, s=u; i>=0; --i){ x[i] = s % 10; s /= 10; }
}void set(BIG_NUM y, BIG_NUM x){ /* y = x */memcpy(y, x, N);
}void div(BIG_NUM x, BIG_NUM y, BIG_NUM z, BIG_NUM r) /* z = x / y */
{int i, q;BIG_NUM ten, s, t;seti(r, 0);//初始化赋零seti(ten, 10);//用于补位的余数*10seti(s, 0);//初始化赋零for(i=0; i<N; ++i){mul(r, ten, r);//余数高位到低位需乘10seti(s, x[i]);/* s = x[i] x[i]为被除数的某一位*/add(r, s, r);/* r = r+s*/for(q=0; q<10 && !sub(r, y, t); ++q)/* r=r-y */ set(r, t);//每次循环t减小,最后一次循环得到的t为余数z[i] = q;}
}

 总结

        大数运算可以扩展的有很多,比如这几个模块没有考虑负数情况,还有结果大于五十位的扩展等等,但核心部分已经解决,这些根据情况而定,我把这些叫做程序预处理,如下:

正负判断(程序预处理)

    四种情况:++;+-;-+;--

    + +:不影响计算

    - +:乘除先剔除符号在运算,加法剔除A的负号,A+B变成B-A,减法剔除A的负号,A-B变成-(A+B)

    + -: 乘除先剔除符号在运算, 加法剔除B的负号,A+B变成A-B,减法剔除B的负号,A-B变成A+B

    - -:乘除先剔除符号在运算,加法剔除负号,A+B变成-(A+B),减法剔除负号,A-B变成B-A;

         模块化的好处就是代码清晰明了,省略了好多冗杂的部分,而且不同函数之间的引用和扩展性能变高。

        总的来说,这道题也是数据思维的一种体现,正确的数据理解和思维,大大降低了程序设计的难度,带来的效果有时候比算法的优化效果更棒!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka-副本分配策略

一、上下文 《Kafka-创建topic源码》我们大致分析了topic创建的流程&#xff0c;为了保持它的完整性和清晰度。细节并没有展开分析。下面我们就来分析下副本的分配策略以及副本中的leader角色的确定逻辑。当有了副本分配策略&#xff0c;才会得到分区对应的broker&#xff0c;…

Move语言中的代币合约:设计和实现指南

系列文章目录 Task1&#xff1a;hello move&#x1f6aa; Task2&#xff1a;move coin&#x1f6aa; Task3&#xff1a;move nft&#x1f6aa; 更多精彩内容&#xff0c;敬请期待&#xff01;✌️ 文章目录 系列文章目录前言什么是 Sui 链&#xff1f;什么是 Move 编程语言&a…

精酿啤酒厂建设攻略——关键步骤与注意点

建设一家精酿啤酒厂&#xff0c;每一步都至关重要。在这里&#xff0c;小编将为您精心梳理建设精酿啤酒厂的详细步骤和关键注意点&#xff0c;助您在啤酒市场的蓝海中乘风破浪。从投资预算的精确规划&#xff0c;到市场渠道的精心布局&#xff0c;从产品特色的精准定位&#xf…

什么是UGFC?模块电脑(核心板)规范标准简介四

1. 概念 UGFC是Unified Gold Finger Core Board的缩写&#xff08;意指&#xff1a;统一接口定义金手指核心板&#xff09;&#xff0c;为武汉万象奥科电子有限公司基于企业标准定义的一种针对嵌入式、低功耗、通用型的小型计算机模块标准&#xff0c;采用204Pin金手指连接器…

数据科学与SQL:组距分组分析 | 区间分布问题

目录 0 问题描述 1 数据准备 2 问题分析 3 小结 0 问题描述 绝对值分布分析也可以理解为组距分组分析。对于某个指标而言&#xff0c;一个记录对应的指标值的绝对值&#xff0c;肯定落在所有指标值的绝对值的最小值和最大值构成的区间内&#xff0c;根据一定的算法&#x…

量子感知机

神经网络类似于人类大脑&#xff0c;是模拟生物神经网络进行信息处理的一种数学模型。它能解决分类、回归等问题&#xff0c;是机器学习的重要组成部分。量子神经网络是将量子理论与神经网络相结合而产生的一种新型计算模式。1995年美国路易斯安那州立大学KAK教授首次提出了量子…

大语言模型---ReLU函数的计算过程及其函数介绍

文章目录 1. 概要2. ReLU定义 1. 概要 **ReLU 作用&#xff1a;**主要用于为神经网络引入非线性能力&#xff0c;作用是将输入中的整数保留原值&#xff0c;负数置为 0。 从而在层与层之间引入非线性&#xff0c;使神经网络能够拟合复杂的非线性关系。 **ReLU使用场景&#xf…

SPSS统计学:连续均匀分布

概念 连续均匀分布是指在某个连续区间上&#xff0c;随机变量取值的概率密度函数是常数的分布。假设连续均匀分布的区间为[a,b]&#xff0c;其中a是区间的下界&#xff0c;b是区间的上界。 方差的推导 连续均匀分布的方差计算中出现数字12&#xff0c;是因为在推导过程中&…

时间请求参数、响应

&#xff08;7&#xff09;时间请求参数 1.默认格式转换 控制器 RequestMapping("/commonDate") ResponseBody public String commonDate(Date date){System.out.println("默认格式时间参数 date > "date);return "{module : commonDate}"; }…

设计模式:4、命令模式(双重委托)

目录 0、定义 1、命令模式包括四种角色 2、命令模式的UML类图 3、代码示例 0、定义 将一个请求封装为一个对象&#xff0c;从而使用户可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 1、命令模式包括四种角色 接…

VSCode汉化教程【简洁易懂】

我们安装完成后默认是英文界面。 找到插件选项卡&#xff0c;搜索“Chinese”&#xff0c;找到简体&#xff08;更具你的需要&#xff09;&#xff08;Microsoft提供&#xff09;Install。 安装完成后选择Change Language and Restart。

海洋通信船舶组网工业4G路由器应用

船舶是浩瀚海洋中探索与贸易的载体&#xff0c;更是船员们生活与工作的家园。为了在广阔的水域中搭建起稳定、高效的网络桥梁&#xff0c;工业4G路由器以卓越的通信组网能力&#xff0c;为船舶组网提供网络支持。 工业4G路由器以其强大的信号发射能力&#xff0c;确保船舶内部…

深入浅出分布式缓存:原理与应用

文章目录 概述缓存分片算法1. Hash算法2. 一致性Hash算法3. 应用场景Redis集群方案1. Redis 集群方案原理2. Redis 集群方案的优势3. Java 代码示例:Redis 集群数据定位Redis 集群中的节点通信机制:Gossip 协议Redis 集群的节点通信:Gossip 协议Redis 集群的节点通信流程Red…

麒麟部署一套NFS服务器,用于创建网络文件系统

一、服务端共享目录 在本例中,kyserver01(172.16.200.10)作为客户端,创建一个目录/testdir并挂载共享目录;kyserver02(172.16.200.11)作为服务端,创建一个共享目录/test,设置为读写权限,要求客户端使用root登录时映射为nobody用户、非root登录时保持不变。 服务端启…

美国AWS EC2 ubuntu 使用密码登陆

1。使用页面登录ec2 2.切换root用户 sudo -i 3.为root用户或者其它用户配置密码 passwd user passwd root 4.修改下面文件的配置vi /etc/ssh/sshd_config PermitRootLogin和PasswordAuthentication 修改为yes 第五步&#xff1a;进入/etc/ssh/sshd_config.d目录&#xff0c;…

圣诞节秘诀

&#x1f570;️你想在2024年圣诞节脱颖而出吗&#xff1f;利用我们的数据洞察&#xff0c;发现今年最受欢迎的礼物&#xff01;无论是在亚马逊、速卖通、Shopify还是直销平台上&#xff0c;我们的排行榜都将帮助您找到最畅销和最受欢迎的产品。立即优化您的库存&#xff0c;以…

Unreal从入门到精通之如何绘制用于VR的3DUI交互的手柄射线

文章目录 前言实现方式MenuLaser实现步骤1.Laser和Cursor2.移植函数3.启动逻辑4.检测射线和UI的碰撞5.激活手柄射线6.更新手柄射线位置7.隐藏手柄射线8.添加手柄的Trigger监听完整节点如下:效果图前言 之前我写过一篇文章《Unreal5从入门到精通之如何在VR中使用3DUI》,其中讲…

堆外内存泄露排查经历

优质博文&#xff1a;IT-BLOG-CN 一、问题描述 淘宝后台应用从今年某个时间开始docker oom的量突然变多&#xff0c;确定为堆外内存泄露。 后面继续按照上一篇对外内存分析方法的进行排查(jemalloc、pmap、mallocpmap/mapsNMTjstackgdb)&#xff0c;但都没有定位到问题。至于…

数据检索是什么意思?数据检索包括哪几个

不少用户会提出这样的疑问&#xff0c;数据检索是什么意思&#xff1f;数据检索即把数据库中存储的数据根据用户的需求提取出来&#xff0c;选择适合的数据库检索方式需要根据具体的需求和场景来进行判断。数据检索的结果会生成一个数据表&#xff0c;既可以放回数据库&#xf…

DimensionX:单图生成任意的3d/4d视图

DimensionX:单图生成任意的3d/4d视图 通俗易懂的来说 在我们的方法中&#xff0c;关键是如何从一张图片生成动态的3D和4D场景。我们使用一个叫做ST-Director的工具&#xff0c;它可以分开处理空间&#xff08;3D&#xff09;和时间&#xff08;4D&#xff09;两个方面。想象一…