C语言——高精度乘法

一、引子

高精度乘法相较于高精度加法和减法有更多的不同,加法和减法是一位对应一位进行操作的,而乘法是一个数的每一位对另一个数的每一位进行操作,需要的计算步骤更多。

二、核心算法

void Calculate(int num1[], int num2[], int numres[], int len1, int len2)
{// 核心乘法算法for (int i = 0; i < len1; i++){for (int j = 0; j < len2; j++){numres[i + j] += num1[i] * num2[j];numres[i + j + 1] += numres[i + j] / 10;numres[i + j] = numres[i + j] % 10;}}
}

这一段代码是高精度乘法核心算法的实现,它模拟了我们手工进行多位数乘法的过程。这里,我们有两个数n1和n2,它们分别以字符串的形式存储,并被转换成整数数组num1和num2,其中低位在前,高位在后(即字符串“123”会被存储成整数数组{3, 2, 1})。然后我们对这两个数组执行乘法。

对于乘法,我们对于num1的每一位(由外层循环 i 控制)与num2的每一位(由内层循环 j 控制)相乘。由于我们是按位计算,所以需要考虑结果的位数(res数组的下标 i + j )。这里考虑结果的位数是最低位数,由于数组的特性,两个数字的最低位在数组中是作为第零位的,而且在数组中两个数的每一位相当于之前都是减少了一位,如果是10 * 10两个两位数相乘理论上结果是三位,但是如果将两数字的位数相加作为结果的位数,那结果就是四(2 + 2)位数,这样就不对了,但是由于数组的特性,将两数字位数相加改成两数字当前索引相加就可以了,10 * 10,索引相加是(1 + 1) = 2,而二作为索引是3位数,结果是三位数,这样就对了。在这里的原理是转换的过程,两个数的位数转成索引要减一,两个数就是减二,而结果的索引转成位数又要加一,这是就相当于减一,在前面直接用位数运算的版本中,结果是四位,这里的就相当于结果的位数减一,结果的位数就变成了三,就对了。

假设两个两位数相乘,结果的位数最低可能是三位,最高是四位,这里是按最低算的。如果放到了最高位就会导致这一步的结果扩大了十倍,对比上面的解释我们发现数组是可以直接实现将每一步结果存到正确的位上的。也就是num1[i] * num2[j]的结果可以直接放到res[i + j]里的这样是正确的。

如果不使用数组而使用数字位数的话,也就是假设 i 和 j 不是索引而是数位,那就不能将(num1的 i 位的数字) * (num2的 j 位的数字)的结果放到res的(i + j)位上,而要把结果放到res的(i + j - 1)位上。

假设是10 * 10 = 100,结果是三位,

num1[0] * num2[0]是0 * 0 = 0,res[0 + 0] = 0,res[0] = 0

num1[1] * num2[0] = 0,res[1 + 0] = 0,res[1] = 0

num1[0] * num2[1] = 0,res[0 + 1] = 0,res[1] = 0

num1[1] * num[1] = 1,res[1 + 1] = 1,res[2] = 1

这是结果就是100

这个乘法的过程是:

1. res[i + j] += n1[i] * n2[j]:这里我们将num1的第i位和num2的第 j 位相乘,然后加到结果的相应位置。由于n1和n2的下标为 i 和 j ,那么对应的结果应该是res[i + j]。这里的结果为res[i + j]就是我们上面解释的体现,用数组的特性使得这样做是正确的。

2. res[i + j + 1] += res[i + j] / 10:这里我们处理进位。如果res[i + j]的结果是两位数(即大于或等于10),我们需要将十位上的数字进位到结果的下一个位置res[i + j + 1]。

3. res[i + j] = res[i + j] % 10:保证结果数组res的每一位都是个位数,即进行模10操作。进位已经在上一步处理过了,这里确保数组res中存储的是当前位的正确数字。

这个过程会一直重复,直到num1和num2中的每一位都相乘。由于进位可能影响到最终结果的位数,结果数组res的实际使用长度可能会比num1和num2的长度总和还要大。所以,我们在定义res数组的时候要确保它有足够的空间来存储可能的最大结果,即num1长度和num2长度的和。

在乘法完成后,结果数组res中存储的是乘法结果的每一位数字,但是顺序是反的,即最低位在数组的第0个位置。在最后,我们需要将结果数组转换回字符串,并且反转回正确的顺序来输出最终的乘积。

三、处理正负

我们同时还要考虑结果的正负,对结果的正负进行判断,影响结果正负的因素是乘数的正负,这里就是同正异负,可以判断好结果的正负,然后将负号在最后打印。

在输入乘数时会有负号,所以要判断乘数是否为负数,然后还要将乘数前的负号去除,防止对之后的计算产生影响。

同时,在处理正负前不能将字符数组反转或者转成整型数组。

int JudgePorN(char arrch1[], char arrch2[])//1代表负,0代表正
{if (arrch1[0] == '-' && arrch2[0] != '-'){arrch1[0] = '0';//将 - (负号)替换为符号0,防止对后面的计算有影响,符号0在后面的计算中不会有影响,因为零会在后面作为前导零去除。注意是'0',如果写成数字0就不对了,数字0是\0的ASIIC码,写成数字0会被转换成\0,\0是字符串的结束符return 1;}else if (arrch1[0] != '-' && arrch2[0] == '-'){arrch2[0] = '0';return 1;}else if (arrch1[0] == '-' && arrch2[0] == '-'){arrch1[0] = '0';arrch2[0] = '0';return 0;}return 0;
}

所以处理正负函数要在字符数组反转函数和转成整型数组函数之前调用。

四、代码实现

#include <stdio.h>
#include <string.h>void DigitReverse(char arr[])//反转字符串,以便后续计算
{int length = (int)strlen(arr);for (int i = 0; i < length / 2; i++){int temp = arr[i];arr[i] = arr[length - i - 1];arr[length - i - 1] = temp;}
}void StringTranstoNumber(char arrchar[],int arrnum[])//将字符数组转换为数字数组
{int length = (int)strlen(arrchar);for (int i = 0; i < length; i++){arrnum[i] = arrchar[i] - '0';}
}void Calculate(int num1[], int num2[], int numres[], int len1, int len2)
{// 核心乘法算法for (int i = 0; i < len1; i++){for (int j = 0; j < len2; j++){numres[i + j] += num1[i] * num2[j];numres[i + j + 1] += numres[i + j] / 10;numres[i + j] = numres[i + j] % 10;}}
}void BigNumMul(char arrch1[], char arrch2[], int res[],int len1,int len2)
{DigitReverse(arrch1);DigitReverse(arrch2);int num1[505] = {0};int num2[505] = {0};StringTranstoNumber(arrch1,num1);StringTranstoNumber(arrch1,num2);Calculate(num1,num2,res,len1,len2);//计算结果
}void Print(int resnum[],int lengthmax)//打印函数
{int i = lengthmax;while (i > 0 && resnum[i] == 0)//去除前导零,因为是按最大位数算的,可能有前导零{i--;}for (; i >= 0; i--){printf("%d",resnum[i]);}
} int JudgePorN(char arrch1[], char arrch2[])//1代表负,0代表正
{if (arrch1[0] == '-' && arrch2[0] != '-'){arrch1[0] = '0';//将 - (负号)替换为符号0,防止对后面的计算有影响,符号0在后面的计算中不会有影响,因为零会在后面作为前导零去除。注意是'0',如果写成数字0就不对了,数字0是\0的ASIIC码,写成数字0会被转换成\0,\0是字符串的结束符return 1;}else if (arrch1[0] != '-' && arrch2[0] == '-'){arrch2[0] = '0';return 1;}else if (arrch1[0] == '-' && arrch2[0] == '-'){arrch1[0] = '0';arrch2[0] = '0';return 0;}return 0;
}int main()
{char ch1[505] = "0";char ch2[505] = "0";scanf("%s",ch1);scanf("%s",ch2);int res[1010] = {0};int len1 = (int)strlen(ch1);int len2 = (int)strlen(ch2);if (len1 == 1 && ch1[0] == '0'){printf("0");}else if (len2 == 1 && ch2[0] == '0'){printf("0");}else if (len1 == 1 && len2 == 1 && ch1[0] == '0' && ch2[0] == '0'){printf("0");}else//非零情况{int judgevalue = JudgePorN(ch1, ch2);//判断结果正负并去除字符串前面的 - (负号)BigNumMul(ch1, ch2, res, len1, len2);int lengthmax = len1 + len2;//乘法结果最大可能是两个乘数的位数和if (judgevalue == 1)//结果为负{printf("-");Print(res, lengthmax);}else//结果为正{Print(res, lengthmax);}}
}

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

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

相关文章

代理IP解决了哪些问题?如何切换IP地址?

代理IP主要解决了以下问题&#xff1a; 1. 隐私保护&#xff1a;通过代理IP&#xff0c;用户可以隐藏自己的真实IP地址&#xff0c;增强网络匿名性&#xff0c;保护个人信息不被泄露。 2. 地理位置限制&#xff1a;某些网站或服务可能会根据用户的IP地址实施地域限制。使用代…

echart图表之仪表盘 pie 双盘 乃至多盘

效果展示&#xff1a; 代码&#xff1a; //首页转速盘 export const pieSpeed (params) > {let demoDataif (params.length ! 0) {demoData params?.map(item > {return {title: item.title,name: item.name,value: item.value,unit: item.unit || ,pos: item.pos,ran…

Android Studio开发之路(六)(合集)界面优化以及启动图标等

一、导航栏背景、字体修改 导航栏、状态栏等背景颜色的修改一般是在themes.xml文件中修改&#xff0c;android一个activity各个部件参考&#xff1a; colorPrimary,colorPrimaryDark等的意义 添加链接描述 但是问题在于&#xff1a;只在这里修改背景颜色的话&#xff0c;可能…

D : B DS二叉排序树_树中第k小的元素

Description 给定一个二叉排序树和一个整数k&#xff0c;要求输出树中第k个最小元素(k从1开始计数)。 Input 第一行输入t&#xff0c;表示有t个测试样例。 第二行起&#xff0c;首先输入n&#xff0c;接着输入n个整数表示一个二叉排序树&#xff0c;接着输入k。 以此类推共…

【数据结构和算法】---二叉树(1)--树概念及结构

目录 一、树的概念及结构1.1 树的概念1.2 树的相关概念1.3 树的表示1.4 树在实际中的运用 二、二叉树的概念及结构2.1 二叉树概念2.2 特殊的二叉树2.3 二叉树的性质2.4 二叉树的存储结构 三、树概念相关题目 一、树的概念及结构 1.1 树的概念 树是一种非线性的数据结构&#…

OpenCV技术应用(9)— 视频的暂停播放和继续播放

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。本节课就手把手教大家如何控制视频的暂停播放和继续播放&#xff0c;希望大家学习之后能够有所收获~&#xff01;&#x1f308; 目录 &#x1f680;1.技术介绍 &#x1f680;2.实现代码 &#x1f680;1.技术介绍…

vue2 按钮限制 点击按钮一前 灰色不可以点击 点击按钮一后 可以点击

代码 <template> <div> <button click"enableButtons">按钮1</button> <button :disabled"!isButton2Enabled" click"ann">按钮2</button> <button :disabled"!isButton3Enabled" c…

Opencv实验合集——实验五:高动态范围

1.概念 高动态范围成像&#xff08;HDRI 或 HDR&#xff09;是一种用于成像和摄影的技术&#xff0c;可以再现比标准数字成像或照相技术更大的动态光度范围。虽然人眼可以适应各种光线条件&#xff0c;但大多数成像设备每通道使用 8 位&#xff0c;因此我们仅限于 256 级。当我…

某电子文档安全管理系统存在任意用户登录漏洞

漏洞简介 某电子文档安全管理系统存在任意用户登录漏洞&#xff0c;攻击者可以通过用户名获取对应的cookie&#xff0c;登录后台。 资产测绘 Hunter语法&#xff1a;web.icon“9fd216c3e694850445607451fe3b3568” 漏洞复现 获取Cookie POST /CDGServer3/LinkFilterServi…

uniapp websocket的使用和封装

在uniapp中socket分为两种形式&#xff0c;第一种适用于只有一个socket链接&#xff0c;第二种适用于多个socket链接。传送门 这里以socketTask为列子封装 在utils新建一个文件 在你要使用的页面引入&#xff0c;我这是聊天那种&#xff0c;所以我在拿到用户信息之后连接sock…

【Linux】whereis命令使用

whereis命令 whereis命令用于查找文件。 使用whereis命令可以查找指定文件、命令和手册页的位置&#xff0c;不能搜索普通文件。 以前学习过 【Linux】 find命令使用 语法 whereis [选项] [文件] find命令 -Linux手册页 命令选项及作用 执行令 whereis --help 执行命…

多媒体信息化建设,动态数据中心,深入理解分布式系统

目录 一、前言二、双活数据中心三、数据备份方式四、设计双活数据中心需要考虑的问题1、延迟和稳定性2、Quorum/ Tie-Breaker3、工作负载 五、动态数据中心六、深入理解分布式系统1、内容介绍2、作者简介 大家好&#xff0c;我是哪吒。 文末送5本《深入理解分布式系统》 一、…

C/C++ BM1反转链表

文章目录 前言题目1.解决方案一1.1 思路阐述1.2 源码 2. 解决方案二2.1 思路阐述2.2 源码 总结 前言 这题是牛客网的BM1&#xff0c;主要涉及到链表的操作以及栈数据结构的使用。 题目 给定一个单链表的头结点pHead(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的…

Flink cdc3.0同步实例(动态变更表结构、分库分表同步)

文章目录 前言准备flink环境docker构建mysql、doris环境数据准备 通过 FlinkCDC cli 提交任务整库同步同步变更路由变更路由表结构不一致无法同步 结尾 前言 最近Flink CDC 3.0发布&#xff0c; 不仅提供基础的数据同步能力。schema 变更自动同步、整库同步、分库分表等增强功…

论文笔记:Accurate Localization using LTE Signaling Data

1 intro 论文提出LTELoc&#xff0c;仅使用信令数据实现精准定位 信令数据已经包含在已在LTE系统中&#xff0c;因此这种方法几乎不需要数据获取成本仅使用TA&#xff08;时序提前&#xff09;和RSRP【这里单位是瓦】&#xff08;参考信号接收功率&#xff09; TA值对应于信号…

vue没有使用fetch报错 Uncaught (in promise) TypeError: Failed to fetch

出现下面的错误&#xff0c;主要也没有用谷歌浏览器什么和发起fetch请求&#xff0c;找了很久没有什么发现 POST https://www.google-analytics.com/mp/collect?measurement_idG-04CMS1PYS6&api_secretpRgvhB8VTii5eSmcTzVaOg net::ERR_BLOCKED_BY_CLIENT Uncaught (in pr…

获投1050万欧元!德国量子公司Kipu Quantum成功研发特定压缩算法

​&#xff08;图片来源&#xff1a;网络&#xff09; 近日&#xff0c;德国量子软件公司Kipu Quantum宣布成功完成种子轮融资&#xff0c;融资总额达1050万欧元&#xff08;约合8000万人民币&#xff09;。该初创公司目前已开发出运行高性能量子计算机所需的压缩算法。该算法…

windows安装、基本使用vim

标题&#xff1a;windows安装、基本使用vim 1.下载并安装GVIM 百度网盘链接 提取码&#xff1a;2apr 进入安装界面&#xff0c;如下&#xff0c;勾选 其它都是默认即可 参考&#xff1b; 2.在powershell中使用vim 参考blog&#xff1a;window10安装vim编辑器 安装好后&…

HTML+CSS做一个冰立方体时钟

文章目录 💕效果展示💕代码展示HTMLJS💕效果展示 💕代码展示 HTML <!DOCTYPE html> <html lang

双三次 Bezier 曲面

双三次 Bezier 曲面的定义 Bezier 曲面是由 Bezier 曲线扩展得到&#xff0c;它是两组正交的 Bezier 曲线控制点构造空间网格生成的曲面 p ( u , v ) ∑ i 0 3 ∑ j 0 3 P i , j B i , 3 ( u ) B j , 3 ( v ) , ( u , v ) ∈ [ 0 , 1 ] [ 0 , 1 ] \begin{equation} \bm{p}…