C语言——高精度乘法

news2024/9/27 15:28:41

一、引子

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

二、核心算法

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.coloradmin.cn/o/1323776.html

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

相关文章

从零开始的Docker Desktop使用,Docker快速上手,Docker介绍和基础使用

目录 1 Docker简介和安装和基础配置1.1 Docker简介1.2 安装Docker Desktop1.3 换源1.4 Docker基础使用1.5 对Docker操作1.5.1 获取当时所有镜像(docker images)1.5.2 拉镜像(docker pull)1.5.3 删除镜像(docker rmi)1.5.4加载镜像(docker run) 1.6 使用交互式容器1.6.1 查看容器…

【2023 英特尔On技术创新大会直播 |我与英特尔的初次相遇】—— AIPC探索下一代的物联网时代

&#x1f308;个人主页: Aileen_0v0 &#x1f525;系列专栏:英特尔技术学习专栏 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 硅谷经济的发展与挑战 Intel开发者云与AI技术的应用 AI压缩技术的发展与应用 英特尔与阿里巴巴在AI领域的合作 AIPC时代的…

司铭宇老师:销售经理培训课程内容

销售经理是销售团队的核心领导&#xff0c;他们的能力和素质直接影响到整个团队的绩效。针对销售经理的培训课程内容应涵盖多个方面&#xff0c;旨在提升销售经理的领导力、团队管理能力、沟通技巧和市场分析能力。以下是一篇关于针对销售经理的培训课程内容的文章&#xff0c;…

逻辑回归代价函数

逻辑回归的代价函数通常使用交叉熵损失来定义。这种损失函数非常适合于二元分类问题。 本篇来推导一下逻辑回归的代价函数。 首先&#xff0c;我们在之前了解了逻辑回归的定义&#xff1a;逻辑回归模型是一种用于二元分类的模型&#xff0c;其预测值是一个介于0和1之间的概率…

ESP32 - Thonny+MicroPython+ESP32开发环境搭建

ThonnyMicroPythonESP32开发环境搭建 ①下载Thonny②下载MicroPython③下载对应驱动④烧录MicroPython到EPS32⑤Thonny与ESP32交互到此为止&#xff0c;我们就搭建好了整个流程 ①下载Thonny 链接&#xff1a;https://thonny.org/ ②下载MicroPython 链接&#xff1a;https:…

2023年第四届 “赣网杯” 网络安全大赛 gwb-web3 Write UP【PHP 临时函数名特性 + 绕过trim函数】

一、题目如下&#xff1a; 二、代码解读&#xff1a; 这段代码是一个简单的PHP脚本&#xff0c;它接受通过GET请求传递的两个参数&#xff1a;‘pass’和’func’&#xff1a; ① $password trim($_GET[pass] ?? );&#xff1a;从GET请求中获取名为’pass’的参数&#xff0…

0086-Java_四种进制介绍

文章目录 1 进制(程序员的基本功)1.1 进制介绍1.2 进制的转换(基本功)1.2.1 进制转换的介绍 1.3 二进制在运算中的说明1.4 原码、反码、补码(重点 难点) 1 进制(程序员的基本功) 1.1 进制介绍 对于整数&#xff0c;有四种表示方式&#xff1a; 二进制&#xff1a;0,1 &#x…

command ‘python.execSelectionInTerminal‘ not found

command python.execSelectionInTerminal not found 问题描述解决方案 问题描述 选择解释器提示&#xff1a; 解决方案 在左侧栏中搜索workspaceUnsupported 可以看到Python在受限制模式下运行 关闭受限制模式 再来看就没有受限制了 这就可以选择解释器了 参考1 参考…

细说 MySQL 用户安全加固策略

这是一篇关于如何加强 MySQL 用户安全的文章&#xff0c;通读全文您可以了解密码复杂度策略、连接控制插件以及密码变更策略的相关知识。本文内容仅供参考&#xff0c;请在操作时以实际环境为准&#xff0c;避免造成经济损失。 作者&#xff1a;余振兴&#xff0c;爱可生 DBA 团…

7-1 抢红包(PTA - 数据结构)

没有人没抢过红包吧…… 这里给出N个人之间互相发红包、抢红包的记录&#xff0c;请你统计一下他们抢红包的收获。 输入格式&#xff1a; 输入第一行给出一个正整数N&#xff08;≤104&#xff09;&#xff0c;即参与发红包和抢红包的总人数&#xff0c;则这些人从1到N编号。…

[每周一更]-(第31期):Mysql安装汇总

写自&#xff1a;20230204 23:25 一. mysql rpm二进制包 rpm -Uvh http://repo.mysql.com/mysql-community-release-el6-5.noarch.rpm yum install mysql-community-server service mysqld start set password password(“123456”)二. mysql yum安装 1、安装查看有没有安装…

Dbvis 链接Oracle数据库

安装 Dbvisualizer 后 1&#xff0c;打开Dbvisualizer&#xff0c;单机左键 图片标注处。 2&#xff0c;点击右键&#xff0c;显示。 3&#xff0c;点击Creat Datebase Connection 4,点击 use wizard &#xff0c;填写 地址&#xff0c;下一步 5&#xff0c;选择 Orcal Thin …

华为atlas300安装教程

1、安装包位置&#xff1a; /data/ai_install_packages 2、添加HwHiAiUser用户&#xff1a; groupadd -g 1000 HwHiAiUser useradd -g HwHiAiUser -u 1000 -d /home/HwHiAiUser -m HwHiAiUser -s /bin/bash 3、安装驱动&#xff1a; ./Ascend-hdk-310p-npu-driver_6.0.0_l…

【小技巧】得力多功能计算器,小数变成10的负幂,应该怎么设置正常显示小数

1.本人计算器如图 2.点击MODE&#xff0c;再次点击可以翻页&#xff0c;找到NORM&#xff0c;如图是3 3.1次方&#xff0c;2是小数点。再摁一下2即可

速通Python基础语法--变量篇

Python设计哲学 解决一个问题&#xff0c;只提供一种方案&#xff1a;变量类型 写法灵活,一行代码表达更多意思,提高语言表达能力:动态类型(两面性) 颜色标识&#xff1a; 紫色&#xff1a;Python与C语言的区别 一、常量与表达式 二、变量 1、认识变量&#xff08;存数据&am…

读书笔记产品经理学习笔记1-忘掉技术,先看客户需求

技术到产品思维的转换 以前做技术的时候&#xff0c;扮演的角色是怎样多快好省的完成开发。现在做产品了&#xff0c;你得自己定产品方案&#xff0c;让别人来开发。最重要的是先弄清楚客户的需求是什么&#xff0c;要解决什么问题&#xff0c;再看产品怎么设计&#xff0c;然…

中国风春节倒计时【实时倒计时】

<head><meta charset="UTF-8"><meta name="apple-mobile-web-app-title

Elasticsearch——索引数据

索引可以说是Elasticsearch中非常重要的模块&#xff0c;一个索引可以视作关系数据库中的一张表&#xff0c;本帖将详细介绍与Elasticsearch索引相关的各种功能等。主要内容如下&#xff1a; 索引映射(mapping)结构的定义方法&#xff0c;常用的各种字段类型和动态映射的使用。…

pytorch实现DCP暗通道先验去雾算法及其onnx导出

pytorch实现DCP暗通道先验去雾算法及其onnx导出 简介实现ONNX导出导出测试 简介 最近在做图像去雾&#xff0c;于是在Pytorch上复现了一下dcp算法。暗通道先验去雾算法是大神何恺明2009年发表在CVPR上的一篇论文&#xff0c;还获得了当年的CVPR最佳论文。 实现 具体原理就不…

微课录课软件盘点,让教学变得更轻松!

“有人知道怎么录制课程吗&#xff1f;上网课的时候&#xff0c;老师讲课的速度很快&#xff0c;有些知识点还没理解&#xff0c;就已经跳过了&#xff0c;这时我就想把网课录下来&#xff0c;课后再进行复习&#xff0c;大家有什么录课的软件推荐吗&#xff1f;” 随着信息技…