基础算法--高精度数据(1)

高精度数据处理一般内容简单,写代码难度较大,可能部分内容涉及基础数学、初等数论等知识。请小心食用。不过本节不会给大家太难的高精度处理,我们第一次接触,不能劝退大家对吧。

高精度算法是指,利用基础或高级的数学计算原理,来解决题目给出的数据量超出计算机正常存储范围的数据的一个方式。

开胃小菜-乘法

那么我们先来写个题练一下吧:信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)

一本通1307-高精度乘法:
题目描述:

输入两个高精度正整数M和N(M和N均小于100位)。求这两个高精度数的积。

输入:

输入两个高精度正整数M和N

输出:

求这两个高精度数的积

大眼一看这不就是输出a*b嘛,但是M和N最大都是100位的数啊,怎么存的下1e100啊。更何况,两个100位数相乘得到的10000位数呢。(1位数相乘最大得到9*9=81,两位数;2位数相乘最大得到99*99=9801,四位数......)

那我们不妨想一下,乘法到底是怎么算的,假设两数为a和b(a的位数>=b的位数),那么取b的个位,乘a的所有位数,以后每次都向左偏移一位,依次取完b的位数个数字,结果相加。(我表达的可能不是很好,但大家都能回想起来惩罚的运算规则了,这就足够了)。给大家个图看一下吧:

编码时,我们选择数组不就行了吗,模拟位数,100位,10000位的位数还是蛮充足的。

下面大家自己写一下代码,我也去写一下,别偷看哦,动手时的你脑子想的更多,远比单纯动脑思考有用。

第一步--逻辑清晰,层次分明

首先我们将主函数的架构搭好,我们的逻辑是怎么样的:

在主函数外,我们还有一些维护数位的数组,中间临时数组,结果数组。并合理分配空间。并设置全局变量参与运算的数据的位数,避免了传参的麻烦。设置结果的位数变量ans_size。

#include <bits/stdc++.h>
using namespace std;int a[100 + 10];//乘数
int b[100 + 10];//被乘数
int t[100 + 10];//中间数
int ans[10000 + 10];//结果
int ans_size;//ans最终的位数
int len_a, len_b;//分别是a的位数和b的位数int main() {init();//初始化a、b数组数据for (int i = 1; i <= len_b; i++) {ans_size = calculate(b[i], i);//依次从b中取一位-b[i],并传入第几位-i//每次更新最终答案位数}Output(ans_size);//从第ans_size位依次往前输出,知道第1位输出完毕,构成的一串字符就是计算的结果return 0;
}

 第二步--根据题意,输入数据

输入的数据位数太多,整型家族的数据都存不下,那我们不妨存在字符串中,字符串存100个字符还不是轻而易举。同时我们保证输入的第一个数据位数大于等于第二个(这是我们参与数学运算时,习惯将长的数a放在上面,短的数b在下面,依次取位b[i]),而且,为了保证数据的高低位,我们将字符串逆置,这样低位在前,高位在后,虽然不符合我们的书写逻辑,但符合我们的运算逻辑。同时不要忘了将数字字符转化为数字时需要减去‘0’(根据ASCII码值进行运算转换)。

void init() {string st1, st2;cin >> st1 >> st2;if (st2.size() > st1.size())swap(st1, st2);//保证数a位数多,保留数学运算习惯reverse(st1.begin(), st1.end());//类似于栈的出入reverse(st2.begin(), st2.end());len_a = st1.size(), len_b = st2.size();for (int i = 0; i < len_a; i++) {a[i + 1] = st1[i] - '0';}for (int i = 0; i < len_b; i++) {b[i + 1] = st2[i] - '0';}
}

第三步--输出简单,提前安排

输出时,我们只需要传入一个参数(结果的位数),不传也可以,直接使用全局变量。

然后为了保证我们的结果位数准确,我们可能会在正确位数前多置零一位,此时我们需要判断,这是几位数,如果是一位数,那是0就是0,不用管,如果大于一位数,那前面的零我就不要了,也就是数组有效位数减一(我们使用while更加保险,if一次也是完全可以的),然后依次输出即可。输出这没什么说的了吧。重要的核心代码还是计算。

void Output(int n) {//输出第一位可能为0,最终未产生多余进位//if(n > 1 && 0 == ans[n]) n--;while (n > 1 && 0 == ans[n]) n--;for (int i = n; i > 0; i--) {cout << ans[i];}cout << endl;
}

第四步--核心代码,返璞归真 

首先将这是b的第几位暂时存下来,因为我们的每一位与乘数的结果临时储存在t中,我们需要从这第idx位开始往ans中放。

给你画个图你理解一下计算的过程:第一位9乘99999,我们的结果从第一位开始放在ans中,第二位9乘99999,我们的结果不放在个位了,从十位开始放。......依次类推,所以第几位b[i]乘a还是有必要存下来的。

存下来之后我们开始第一步:计算中间结果:(x为传进来的b的某一位)

本位结果t[i]=x*a[i]+上一位进位t[i-1]/10

上一位结果t[i-1]更新为t[i-1]%=10。(因为我们是十进制运算)

当x与a所有位上的数相乘完之后,我们不确定最高位存储的数据是不是一位数,(有可能是两位数),我们需要额外多维护一位,

第二步,将中间结果加到最终结果中:看上文,我们从第几位开始加?对的,第idx位(传的是b的第几位数,我就从第几位加)

while循环是为了将临时结果全部加到最终结果中

下面不加if判断也行,但是加上更容易我们理解。

这次不需要乘,只需要我们相加,然后满足十进制,跟上一步的思路差不多

最后也需要多维护一位。并返回最高位的数字。

int calculate(int x, int idx) {int ans_start_pos = idx;//答案从第几位开始加for (int i = 1; i <= len_a; i++) {//依次进位t[idx] = (x * a[i] + t[idx - 1] / 10);t[idx - 1] %= 10;idx++;}/*中间值最终进位*/t[idx] = t[idx - 1] / 10;t[idx - 1] %= 10;int cur_pos = ans_start_pos;//就是初始的idxwhile (cur_pos <= idx) {if (ans[cur_pos - 1] > 9) {ans[cur_pos] += ans[cur_pos - 1] / 10;ans[cur_pos - 1] %= 10;}ans[cur_pos] += t[cur_pos];cur_pos++;}/*结果最终进位*/ans[cur_pos] = ans[cur_pos - 1] / 10;ans[cur_pos - 1] %= 10;return cur_pos;
}

参考答案--乘法

总的代码如下:(有一些赘余的变量,但无伤大雅,考虑一下将中间结果数组去掉,只保留结果数组能不能运算?指定是能的,作为你学会本题思路后的额外思考)

#include <bits/stdc++.h>
using namespace std;int a[100 + 10];//乘数
int b[100 + 10];//被乘数
int t[100 + 10];//中间数
int ans[10000 + 10];//结果
int ans_size;//ans最终的位数
int len_a, len_b;//分别是a的位数和b的位数
void init() {string st1, st2;cin >> st1 >> st2;if (st2.size() > st1.size())swap(st1, st2);//保证数a位数多,保留数学运算习惯reverse(st1.begin(), st1.end());//类似于栈的出入reverse(st2.begin(), st2.end());len_a = st1.size(), len_b = st2.size();for (int i = 0; i < len_a; i++) {a[i + 1] = st1[i] - '0';}for (int i = 0; i < len_b; i++) {b[i + 1] = st2[i] - '0';}
}
int calculate(int x,int idx) {int ans_start_pos = idx;//答案从第几位开始加for (int i = 1; i <= len_a; i++) {//依次进位t[idx] = (x * a[i] + t[idx - 1] / 10);t[idx - 1] %= 10;idx++;}/*中间值最终进位*/t[idx] = t[idx - 1] / 10;t[idx - 1] %= 10;int cur_pos = ans_start_pos;while (cur_pos <= idx) {if (ans[cur_pos - 1] > 9) {ans[cur_pos] += ans[cur_pos - 1] / 10;ans[cur_pos - 1] %= 10;}ans[cur_pos] += t[cur_pos];cur_pos++;}/*结果最终进位*/ans[cur_pos] = ans[cur_pos - 1] / 10;ans[cur_pos - 1] %= 10;return cur_pos;
}
void Output(int n) {//输出第一位可能为0,最终未产生多余进位//if(n > 1 && 0 == ans[n]) n--;while (n > 1 && 0 == ans[n]) n--;for (int i = n; i > 0; i--) {cout << ans[i];}cout << endl;
}
int main() {init();//初始化a、b数据for (int i = 1; i <= len_b; i++) {ans_size=calculate(b[i],i);//依次从b中取一位b[i],第几位i}Output(ans_size);return 0;
}

 提交结果:AC,通过了。


好不容易哦,这才一道简单的乘法,就这么难理解了?但你从中学到的不仅仅只有这一点。例如:你知道了用数组元素存储数位;你知道了朴实无华的运算规律/方法;你知道了完成一道题的分析步骤;你初步知道如何处理高精度数据了......只要你认真看完了,思考了,学会了,你收获的远不止这些。哪里不懂,尽管留言,我看到就回复你。

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

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

相关文章

盘古信息IMS MCM制造协同管理系统:为中小企业数字化转型量身打造的数字化方案

近年来&#xff0c;全球经济的不稳定性&#xff0c;给中小企业的经营和发展带来了巨大的挑战。为提升企业竞争力&#xff0c;中小企业纷纷谋求数字化转型路径&#xff0c;优化生产流程、提高运营效率、降低生产成本&#xff0c;以应对变幻莫测的市场环境。IMS MCM是盘古信息为广…

进阶-4.视图、存储过程、存储函数、触发器

视图、存储过程、存储函数、触发器 1.视图1.1 介绍1.2 语法1.3 视图的检查选项1.4 视图的更新1.5 视图作用1.6 案例 2.存储过程21. 介绍2.2 特点2.3 语法2.4 变量2.4.1 系统变量2.4.2用户自定义变量2.4.3 局部变量 2.5参数2.6条件语句2.6.1 if 语法2.6.2 case 2.7循环结构2.7.1…

通过IDEA创建spring boot的web项目

1.Fle->New->Project,选择Maven&#xff0c;点击Next 2.修改项目名称&#xff0c;点击Finish 3.项目创建完毕&#xff0c;等待Maven下载完成 4.修改pom.xml文件&#xff0c;改成如下内容 <?xml version"1.0" encoding"UTF-8"?> <pr…

增强管道数据流转(EPDR)技术的设计局限和替代

在前文中&#xff0c;我们介绍了EPDR技术的起源&#xff0c;以及使用该技术驱动的业余软件无线电平台专栏。已有玩家通过踩坑证明&#xff0c;进程管道交换数据时间延迟大&#xff0c;构造时间敏感系统难。除非采用传统的紧耦合设计及更大的颗粒度&#xff0c;否则很难在期望的…

Openstack 与 Ceph集群搭建(中): Ceph部署

文章目录 一、部署前说明1. ceph 版本选择依据2. ceph网络要求3. 硬件要求 二、部署架构三、部署过程1. 通用步骤2. 部署管理节点创建账号安装Cephadm运行bootstrap 3. 登录Ceph web4. 将其他节点加入集群同步ceph key安装ceph CLI命令行添加主机节点到集群添加OSD节点将监控节…

【Canvas与艺术】环形橄榄枝纹饰

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>环形橄榄枝(draft2)</title><style type"text/css&quo…

安卓蓝牙日志的获取方法

有过蓝牙调试经历的同学们可能都知道&#xff0c;在安卓系统中&#xff0c;在手机的设置–>开发人员页面下有一个开启蓝牙HCI信息收集日志选项开关&#xff0c;如下图中标红处&#xff0c; 打开该开关&#xff0c;就可以收集本机发送和接收的蓝牙HCI包。蓝牙包的数据会保存在…

git提交本地项目到远程仓库

1、查看项目目录&#xff0c;是否存在.git文件夹&#xff08;若存在则删除&#xff09; 2、登录git并新建一个空白项目 3、idea创建本地git仓库&#xff08;选择本地项目&#xff09; 4、添加要提交的项目&#xff08;项目右键&#xff09; 5、提交代码到本地仓库 6、配置远程…

轻松实现微服务间的无缝通信:OpenFeign入门指南

OpenFeign 前言1、导入依赖2、开启feign调用3、编写OpenFeign客户端4、Fegin接口实现5、Feign接口调用 前言 Spring Cloud OpenFeign是一种基于Spring Cloud的声明式REST客户端&#xff0c;它简化了与HTTP服务交互的过程。它将REST客户端的定义转化为Java接口&#xff0c;并且…

css 宫格样式内容上下结构

结构 <div class"sc-content-group"><div class"sc-content-item"><div class"sc-item-img"><el-image :src"src" :preview-src-list"[src]"></el-image></div><div class"s…

datax关于postsql数据增量迁移的问题

看官方文档是不支持的 数据源及同步方案_大数据开发治理平台 DataWorks(DataWorks)-阿里云帮助中心 (aliyun.com) 看了下源码有个postsqlwriter 看了下也就拼接sql 将 PostgresqlWriter中的不允许更新先注释了 让他过去先 然后看到 WriterUtil中的对应方法 getWriteTemplat…

咸鱼之王手游内购修复无bug运营版联网架设+后台

今天给大家带来一款单机游戏的架设&#xff1a;咸鱼之王手游。 另外&#xff1a;本人承接各种游戏架设&#xff08;单机联网&#xff09; 本人为了学习和研究软件内含的设计思想和原理&#xff0c;带了架设教程仅供娱乐。 教程是本人亲自搭建成功的&#xff0c;绝对是完整可…

【代码随想录训练营第42期 Day38打卡 - 动态规划Part6 - LeetCode 322. 零钱兑换 279.完全平方数 139.单词拆分

目录 一、做题心得 二、题目与题解 题目一&#xff1a;322. 零钱兑换 题目链接 题解&#xff1a;动态规划--完全背包 题目二&#xff1a; 279.完全平方数 题目链接 题解&#xff1a;动态规划--完全背包 题目三&#xff1a;139.单词拆分 题目链接 题解&#xff1a;动…

qt-16可扩展对话框--隐藏和展现

可扩展对话框 知识点extension.hextension.cppmain.cpp运行图初始化隐藏展现--点击--详细按钮 知识点 MainLayout->setSizeConstraint(QLayout::SetFixedSize);//固定窗口大小 extension.h #ifndef EXTENSION_H #define EXTENSION_H#include <QDialog>class Extens…

你是如何更精准地指引模型,激发其无尽的创造力?

随着大型语言模型日益凸显其重要性&#xff0c;发掘并充分利用它们的潜力&#xff0c;很大程度上依赖于我们如何巧妙构思和构造指令——即Prompt的精炼艺术。优化Prompt撰写技巧&#xff0c;将能够更好地引导大模型&#xff0c;为各类应用场景生成高质量的文本输出。分享出你的…

【STM32】C语言基础补充

学习过程中发现自己好些需要用到的C语言语法、特征都不太熟练了&#xff0c;特意记录一下&#xff0c;免得忘记了&#xff0c;以后遇到了新的也会继续更新 目录 1 全局变量 2 结构体 3 静态变量 4 memset()函数 5 使用8位的存储器存16位的数 1 全局变量…

Excel“取消工作表保护”忘记密码并恢复原始密码

文章目录 1.前言2.破解步骤3. 最终效果4.参考文献 1.前言 有时候别人发来的Excel中有些表格不能编辑&#xff0c;提示如下&#xff0c;但是又不知道原始密码 2.破解步骤 1、打开您需要破解保护密码的Excel文件&#xff1b; 2、依次点击菜单栏上的视图—宏----录制宏&#xf…

Keil C51 插件 快速复制一行

此插件解决的问题 目前 Keil 软件 只可以 先选中一行&#xff0c;再Ctrl C Ctrl V , 太麻烦了 Keil 插件 -- Python 代码 import sys# 插入当前行内容 def insert_line(current_file_path, line_number):line_to_insert # 读取文件内容with open(current_file_path, r, enc…

微信小游戏授权问题

微信小程序获取用户相关信息的接口&#xff0c;如wx.getUserCloudStorage&#xff0c;报错&#xff1a;please go to mp to announce your privacy usage。 需要在微信公众平台设置用户隐私保护。

APP支付宝授权获取code uniapp

1.点击使用plus.runtime跳转打开支付宝 //打开支付宝授权&#xff0c;在支付宝APP中授权后会在支付宝中跳转到你填写的h5地址//urls是授权地址可以后端拼接也可以前端写死 //以下是一个拼接示例&#xff0c;需修改app_id的值和redirect_uri的值即可 //app_id是商户的APPID&…