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

      为什么会有大数呢?因为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.rhkb.cn/news/476799.html

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

相关文章

IntelliJ+SpringBoot项目实战(四)--快速上手数据库开发

对于新手学习SpringBoot开发&#xff0c;可能最急迫的事情就是尽快掌握数据库的开发。目前数据库开发主要流行使用Mybatis和Mybatis Plus,不过这2个框架对于新手而言需要一定的时间掌握&#xff0c;如果快速上手数据库开发&#xff0c;可以先按照本文介绍的方式使用JdbcTemplat…

flex布局 昵图网【案例】

效果展示 只是个大概&#xff0c;可自己完善。 昵图网 代码展示 <body><!-- https://static.ntimg.cn/original/images/soso.png --><div class"container"><div class"header"><!-- <div class"logo"><i…

[第五空间 2021]pklovecloud 详细题解

知识点: 构造POP链 PHP类的作用域 NULL强比较 目录穿越 源码如下: <?php include flag.php; class pkshow { function echo_name() { return "Pk very safe^.^"; } } class acp { protected $cinder; public $neutron;public $n…

dockerfile构建Nginx镜像练习二(5-2)

环境准备&#xff1a; (1)保证拥有centos基础镜像 docker images | grep centos (2)服务器保证可以连接外网 1.创建工作目录 mkdir nginx cd nginx 2.在工作目录中创建并编写Dockerfile文件 vim dockerfile #定义基础镜像 FROM centos:7#维护者信息(可缺省) MAINTAINER d…

Android Surfaceflinger显示图层合成方式

Android SurfaceFlinger是Android系统中负责窗口管理和图像合成的核心组件。它接收来自不同应用的图层数据&#xff0c;并将这些图层合并成一个单一的图像&#xff0c;然后输出到显示设备上。SurfaceFlinger的合成方式主要涉及两种&#xff1a;Client合成和Device合成。 adb s…

wsl安装

一. wsl简介 1. wsl和wsl2的区别 wsl需要把linux命令翻译为windows命令&#xff0c;性能差一些。 wsl2直接使用linux内核&#xff0c;不需要翻译&#xff0c;性能好&#xff0c;但开销相对大一点&#xff0c;因为需要多运行一个hyper-v虚拟机 (并非完整的虚拟机&#xff0c;是…

任务通知的本质(任务通知车辆运行) 软件定时器的本质(增加游戏音效)

任务通知的本质 没有任务通知 所谓"任务通知"&#xff0c;你可以反过来读"通知任务"。 我们使用队列、信号量、事件组等等方法时&#xff0c;并不知道对方是谁。使用任务通知时&#xff0c;可 以明确指定&#xff1a;通知哪个任务。 使用队列、信号量、…

Kubernetes的pod控制器

文章目录 一&#xff0c;什么是pod控制器二&#xff0c;pod控制器类型&#xff08;重点&#xff09;1.ReplicaSet2.Deployment3.DaemonSet4.StatefulSet5.Job6.Cronjob 三&#xff0c;pod与控制器的关系1.Deployment2.SatefulSet2.1StatefulSet组成2.2headless的由来2.3有状态服…

【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录

背景 Jetbrain IDE 支持生成 Test 类&#xff0c;其中选择JUnit5 和 JUnit&#xff0c;但是感觉这不是标准的单元测试&#xff0c;因为接口命名吧。 差异对比 两者生成的单测API名称同原API&#xff0c;没加test前缀的。使用差异主要表现在&#xff1a; setUp &#xff06; …

知识中台在多语言客户中的应用

在全球化的商业环境中&#xff0c;企业面临着多语言客户服务的挑战。HelpLook知识中台作为一种智能化解决方案&#xff0c;为企业提供了一个强大的工具&#xff0c;以实现多语言客户服务的自动化和优化。 一、多语言客户服务的重要性 多语言客户服务对于跨国企业至关重要&…

使用 Elastic AI Assistant for Search 和 Azure OpenAI 实现从 0 到 60 的转变

作者&#xff1a;来自 Elastic Greg Crist Elasticsearch 推出了一项新功能&#xff1a;Elastic AI Assistant for Search。你可以将其视为 Elasticsearch 和 Kibana 开发人员的内置指南&#xff0c;旨在回答问题、引导你了解功能并让你的生活更轻松。在 Microsoft AI Services…

【K8S问题系列 |18 】如何解决 imagePullSecrets配置正确,但docker pull仍然失败问题

如果 imagePullSecrets 配置正确&#xff0c;但在执行 docker pull 命令时仍然失败&#xff0c;可能存在以下几种原因。以下是详细的排查步骤和解决方案。 1. 检查 Docker 登录凭证 确保你使用的是与 imagePullSecrets 中相同的凭证进行 Docker 登录&#xff1a; 1.1 直接登录…

Redis的特性ubuntu进行安装

文章目录 1.六大特性1.1内存存储数据1.2可编程1.3可扩展1.4持久化1.5集群1.6高可用1.7速度快 2.具体应用场景&#xff08;了解&#xff09;3.Ubuntu安装Redis3.1安装指令3.2查看状态3.3查找配置文件3.4修改文件内容3.5重启服务器生效3.6安装客户端并进行检查 4.Redis客户端介绍…

【ASE】第八课_冰(ice)的效果

今天我们一起来学习ASE插件&#xff0c;希望各位点个关注&#xff0c;一起跟随我的步伐 今天我们来学习一个简单的冰的效果&#xff0c;这个是根据油管上的视频制作的 可在我的资源里下载模型&#xff0c;贴图&#xff0c;材质 思路 1.物体表面结冰的效果&#xff0c;也就是…

回溯法基础入门解析

回溯法 前 言 回溯法也可以叫做回溯搜索法&#xff0c;它是一种搜索的方式。回溯是递归的副产品&#xff0c;只要有递归就会有回溯。回溯法&#xff0c;一般可以解决如下几种问题&#xff1a; 组合问题&#xff1a;N个数里面按一定规则找出k个数的集合切割问题&#xff1a;一…

Redis原理及应用

Redis简介 Redis是开源的&#xff08;BSD许可&#xff09;&#xff0c;数据结构存储于内存中&#xff0c;被用来作为数据库&#xff0c;缓存和消息代理。它支持多种数据结构&#xff0c;例如&#xff1a;字符串&#xff08;string&#xff09;&#xff0c;哈希&#xff08;hash…

Ubuntu ESP32开发环境搭建

文章目录 ESP32开发环境搭建安装ESP-IDF搭建一个最小工程现象 ESP32开发环境搭建 最近有个小项目需要用到能够联网的mcu驱动&#xff0c;准备玩玩esp的芯片&#xff0c;记录下ESP32开发环境搭建的过程。 ESP-IDF 是乐鑫科技为其 ESP32 系列芯片提供的官方开发框架。这个框架主…

【C#设计模式(14)——责任链模式( Chain-of-responsibility Pattern)】

前言 责任链模式通过将请求和处理者解耦&#xff0c;关联多个处理者形成一个链条&#xff0c;使每个处理者都有机会处理请求&#xff0c;避免了将所有处理逻辑集中在一个对象中的复杂性。 代码 //请求者 public class Requestor {private string content;public string Cont…

用python将一个扫描pdf文件改成二值图片组成的pdf文件

使用墨水屏读书现在似乎越来越流行&#xff0c;这确实有一定的好处&#xff0c;例如基本不发热&#xff0c;电池续航时间超长&#xff0c;基本不能游戏所以有利于沉浸式阅读&#xff0c;还有不知道是不是真的有用的所谓防蓝光伤害。但是&#xff0c;如果阅读的书籍是扫描图片组…

vue3封装Element Plus table表格组件

支持绝大部分Element Plus原有设置属性&#xff0c;支持分页&#xff0c;支持动态适配高度 效果展示 组件代码&#xff1a; <template><div class"table-wrap" ref"tableWrap"><el-tableclass"w100 h100":data"tableInfo.…