首页 > 其他分享 >高精度减法(C语言实现)

高精度减法(C语言实现)

时间:2023-11-05 09:23:44浏览次数:28  
标签:return 高精度 int C语言 len3 len2 len1 减法

高精度减法(C语言实现)

介绍

众所周知,整数在C和C++中以intlonglong long三种不同大小的数据存储,数据大小最大可达2^64,但是在实际使用中,我们仍不可避免的会遇到爆long long的超大数运算,这个时候,就需要我们使用高精度算法,来实现巨大数的运算。

高精度的本质是将数字以字符串的形式读入,然后将每一位分别存放入int数组中,通过模拟每一位的运算过程,来实现最终的运算效果。

书接上回,我们今天继续讲解高精度减法的C语言实现:


代码实现

#include<stdio.h>
const int N = 100001;

int cmp(int a[], int b[], int len1, int len2)
{//大小比较函数
	if (len1 > len2)//先对比长度
		return 0;
	else if (len1 < len2)//长度不一样直接返回结果
		return 1;
	else//长度一致则依次比较每一位大小
	{
		for (int i = len1 - 1; i >= 0; i--)
		{
			if (a[i] > b[i])
				return 0;
			if (a[i] < b[i])
				return 1;
		}
	}
	return 0;//如果完全一致则返回0,避免减法函数中调用导致无限递归
}

int minus(int a[], int b[], int c[], int len1, int len2)
{//高精度减法函数
	if (cmp(a, b, len1, len2))//减法函数只计算大减小,小减大则反过来,然后输出时加负号
		return minus(b, a, c, len2, len1);
	int t = 0;//t标识是否借位
	for (int i = 0; i < len1; i++)
	{
		c[i] = (a[i] - b[i] + t + 10) % 10;//c[i]表示这一位运算结果
		if (a[i] - b[i] + t < 0) t = -1;//计算是否借位
		else t = 0;
	}
	int len3 = len1;
	while (c[len3 - 1] == 0)//去除前导0,返回结果的位数
	{
		if (len3 == 1) return len3;
		len3--;
	}
	return len3;
}

int main()
{
	char str1[N], str2[N];//----------------------------
	int a[N] = { 0 }, b[N] = { 0 }, c[N] = { 0 };
	char x;
	int len1 = 0, len2 = 0;
	do
	{
		scanf("%c", &x);
		str1[len1++] = x;

	} while (x != '\n');
	do//                                数据读入部分不作赘述
	{
		scanf("%c", &x);
		str2[len2++] = x;

	} while (x != '\n');
	len1--; len2--;
	for (int i = len1 - 1; i >= 0; i--)
		a[i] = str1[len1 - i - 1] - '0';
	for (int i = len2 - 1; i >= 0; i--)
		b[i] = str2[len2 - i - 1] - '0';//---------------
	int len3 = minus(a, b, c, len1, len2);//执行高精度减法函数
	if (cmp(a, b, len1, len2))//大小比较函数
		printf("-");//结果为负数则打个负号先
	for (int i = len3 - 1; i >= 0; i--)
		printf("%d", c[i]);
	return 0;
}

思路解析

鉴于在高精度加法一篇中我们已经讲解过了数据的读入,所以我们这一篇不再赘述,没看过上一篇的可以点击下方链接:

高精度加法(C语言实现) - 凉茶coltea


高精度减法思路和高精度加法基本一致,区别就是加法考虑进位,减法考虑退位,以及减法的结果的位数变动是极大的。

我们对每一位分别计算,得出结果,存入新数组c,同时用临时变量t来标识是否借位。

但小数减大数的结果是负数,在实际操作中十分不便,所以我们另外声明一个cmp函数来比较二者大小,如果被减数比较小,那我们就可以用减数减去被减数,输出结果前先输出一个负号,达到同样的效果。


数据的读入上,高精度加减乘除基本一模一样,所以我们直接跳到第一个关键部分,大小比较函数:

int cmp(int a[], int b[], int len1, int len2)
{//大小比较函数
	if (len1 > len2)//先对比长度
		return 0;
	else if (len1 < len2)//长度不一样直接返回结果
		return 1;
	else//长度一致则依次比较每一位大小
	{
		for (int i = len1 - 1; i >= 0; i--)
		{
			if (a[i] > b[i])
				return 0;
			if (a[i] < b[i])
				return 1;
		}
	}
	return 0;//如果完全一致则返回0,避免减法函数中调用导致无限递归
}

在数据的读入中,我们已经知道了两数的位数,那就可以通过比较位数来判断二者大小谁长谁大

倘若二者长度一致,那就依次比较每一位的大小,也就是比较二者的字典序。

倘若二者完全一致,那我们返回0,原因后面说。


有了大小比较函数,我们就可以保证计算时是大数减去小数了,这样,我们就规避了负数的困扰,可以更轻松地实现高精度减法的函数:

int minus(int a[], int b[], int c[], int len1, int len2)
{//高精度减法函数
	if (cmp(a, b, len1, len2))//减法函数只计算大减小,小减大则反过来,然后输出时加负号
		return minus(b, a, c, len2, len1);
	int t = 0;//t标识是否借位
	for (int i = 0; i < len1; i++)
	{
		c[i] = (a[i] - b[i] + t + 10) % 10;//c[i]表示这一位运算结果
		if (a[i] - b[i] + t < 0) t = -1;//计算是否借位
		else t = 0;
	}
	int len3 = len1;
	while (c[len3 - 1] == 0)//去除前导0,返回结果的位数
	{
		if (len3 == 1) return len3;
		len3--;
	}
	return len3;
}

如你所见,第一步就是对二者大小的判断,如果被减数比减数小,我们直接改变入参的顺序来改变二者位置。

倘若二者完全一致时cmp返回1,那么再调换位置后,minus函数将继续调用cmp函数来判断二者大小,每次都会返回1,导致无限递归,这就是我们规定完全一致时返回0的原因。

其中我们用c[i] = (a[i] - b[i] + t + 10) % 10;来计算结果的第i位,之所以要+10,是模拟结果为负时向前一位借10的过程,而如果(a[i] - b[i] + t)不为负数,那因为%10的存在,也不会产生影响。

下一行if (a[i] - b[i] + t < 0)也很好理解,若是(a[i] - b[i] + t)为负数,那就需要向前一位借位,那我们就标记t=-1,来影响下一位的结果计算即可。

最后我们需要去除前导0,首先因为运算数都是正整数,所以结果最大位数也就和被减数一样,所以我们从被减数的最高位数开始判断结果c,如果为0,那就把返回的长度len3减去1,而值得注意的是,若是结果只有1位了那就不能减了,因为这意味着结果为0


那此时我们就已经完成了高精度减法的运算,将结果存入了数组c,但别忘了结果正负的判断:

	if (cmp(a, b, len1, len2))//大小比较函数
		printf("-");//结果为负数则打个负号先

如果被减数比减数小,我们需要提前把负号补上。

那就此,大功告成。


结尾

那么以上便是对高精度减法算法的介绍,本文由凉茶coltea撰写,思路来自AcWing,大佬yxc的课程。

标签:return,高精度,int,C语言,len3,len2,len1,减法
From: https://www.cnblogs.com/coltea/p/17810234.html

相关文章

  • 实验3 C语言函数应用编程
    任务11#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN8067voidprint_text(intline,intcol,chartext[]);8voidprint_spaces(intn);9voidprint_blank_lines(intn......
  • 高精度加法(C语言实现)
    高精度加法(C语言实现)介绍众所周知,整数在C和C++中以int,long,longlong三种不同大小的数据存储,数据大小最大可达2^64,但是在实际使用中,我们仍不可避免的会遇到爆longlong的超大数运算,这个时候,就需要我们使用高精度算法,来实现巨大数的运算。高精度的本质是将数字以字符串的形式......
  • C语言小案例
    1.设计一个递归函数,计算Ackerman的值。Ackerman函数定义如下:       n+1                 m=0A(m,n)=A(m-1,1)             m≠0,n=0       A(m-1,A(m,n-1))        m≠0,n......
  • B站C语言第十课
    1,函数#include<stdio.h>#include<string.h>#include<stdlib.h>//intAdd(intx,inty){ intz=0; z=x+y; returnz;}intmain(){ inta=10; intb=20; intsum=Add(a,b); printf("%d\n",sum); return0;}2,牢记......
  • 贪心算法(C语言)
    一、会议安排问题1.1问题(1)对于每个会议i,起始时间bi和结束时间ei,且bi<ei(2)[bi,ei]与[bj,ej]不相交,则会议i和会议j相容,bi≥ej或bj≥ei(3)目标:在有限的时间内,尽可能多地安排会议1.2分析选择最早结束的会议1.3实现(1)初始化:按结束时间递增排序(2)选中第一......
  • C语言笔记3
    关键字1.C语言预先规定的,具有特定意义的字母组合(32个)。2.保留给语言本身使用,也称为保留字。标识符定义:为程序的构成成分命名。变量变量是程序执行期间其值可以改变的量,必须先定义后使用。变量定义本格式类型说明符变量名1变量名2...如inta,b,c;floatx;功能:指定......
  • java获得之前的时间, 时间的减法运算实现
    //方法一SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd");StringmaxDateStr="2018-01-01";StringminDateStr="";Calendarcalc=Calendar.getInstance();try{......
  • 实验3—C语言函数应用编程
    1、实验任务1源代码1#include<stdio.h>2#include<stdlib.h>3#include<time.h>4#include<windows.h>5#defineN806voidprint_text(intline,intcol,chartext[]);//函数声明7voidprint_spaces(intn);//函数声明8voidprint_b......
  • C语言 循环队列
    什么是队列队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。什么是循环队列在实际使用队列时,为了使队列空间能重复使用,往往对......
  • C语言基础之基础的输入输出
    前言学一门编程语言,不能编写让用户输入数据然后输出处理后的数据的程序那么就等于没学,而在C语言中可以用printf()和scanf()函数进行输入和输出操作。这两个函数是内置的库函数,定义在stdio.h(头文件)中。printf()函数printf()函数用于输出操作。它将给定的语句打印到控制台......