前言
加,减,乘,除这些运算我们自然信手捏来,就拿加法来说,我们要用c语言编程算a+b的和,只需让sum = a+b即可,可是这是局限的,我们都知道int的表示的最大值为2147483647(32位和64位机器)。但是如果我们要算的数超过了这个值该怎么办?这时会有人说:用long long不得了么?,但是你想想假如你面对的是几百位甚至几千位的整数时,用long long也无济于事,这时候就需要用到我们的高精度算法了。那么话不多说,让我们开始吧!
文章目录
- 1,加法
- 2,减法
- 3,尾声
1,加法
首先让我们回忆回忆小学的时候我们时怎样进行加法用算的。
我们先把两个数弄成两行然后按位相加,如果某一位相加后大于9那么就往前进一位,下一位+1,这一位-10.
我们的高精度加法也是采用这个思路。
因为int 和long long不能够满足我们的高精度加法,那么我们只能另辟蹊径,我们知道数组可以很长,如果我们把需要相加的两个数字分别存进两个数组之中,数字的个位放在下标0,数字的十位放在下标1,…以此类推。到最后我们再把两个数组相同下标相加求和,如果大于9就往前进一位。相加完之后我们就能够得到我们的所需要求的和了。
但是怎么把数字的个位放在下标为0的地方呢?我们可以先创建一个char类型的数组,然后用%s进行读取,读取完之后将其内容翻转即可。(既然是字符数组那么就要留意‘1’不等于1,‘1’-‘0’=1)
读取完两个数字之后我们想把他们相加,可是他们的位数可能不一样,比如"10001"和"100",为了方便我们需要将短的字符串变长,在其前头补上’0’(即把"100"改成"00100")。
下面我用代码的方式给大家展示。
#include <stdio.h>
#include<string.h>
void my_reverse(char* arr, int len)//简单的翻转函数
{
for (int i = 0; i < len - 1; i++, len--)
{
char temp = arr[i];
arr[i] = arr[len - 1];
arr[len - 1] = temp;
}
}
void print_sum(int len1, char* arr1, char* arr2)
{
int q = 0;
for (int i = 0; i < len1; i++)
{
arr1[i] += arr2[i];// '1'+'1'-'0'='2'
arr1[i] -= '0';
if (arr1[i] > '9')//大于10往前进一位
{
arr1[i] -= 10;
if (i != len1 - 1)
arr1[i + 1] += 1;
else//如果i=len1-1那么arr1[i]中存放的是'\0'需要+'1'来进一位
{
arr1[i + 1] += '1';
q++;//长度+1,这里如果写len1++会导致循环失败
}
}
}
for (int i = len1 - 1 + q; i >= 0; i--)//倒序打印
{
printf("%c", arr1[i]);
}
}
int main()
{
char arra[100] = { 0 }, arrb[100] = { 0 };//分别储存a,b的值
scanf("%s %s", arra, arrb);
int lena = strlen(arra);//计算a和b的长度
int lenb = strlen(arrb);
my_reverse(arra, lena);//将a和b进行翻转方便进行加法运算
my_reverse(arrb, lenb);
if (lena > lenb)//如果a的长度大于b的长度,在b后面补'0'方便计算
{
for (int i = lenb - 1; i < lena - 1; i++)
{
arrb[i + 1] += '0';
lenb++;
}
}
else if (lena < lenb)//如果b的长度大于a的长度,在a后面补'0'方便计算
{
for (int i = lena - 1; i < lenb - 1; i++)
{
arra[i + 1] += '0';
lena++;
}
}
print_sum(lena, arra, arrb);//相加并打印
return 0;
}
我们自己写完之后,可以去洛谷 p1061题(A+B Problem(高精))进行自测。看看是否能通过。
2,减法
学会了高精度加法,自然高精度减法也不在话下。还是这种方法。
大致思路与加法相同,创建两个数组储存a和b,然后将两者相减即可,每一位小于0的话,前一位-1,这一位+10。
但是我们会发现,我们算a-b的时候如果b大于a会出现负数的情况,这会让我们不方便计算,那我们想一想,a-b是不是等于-(b-a)呢?如果b>a我们可以直接算b-a然后在结果的前面加上一个‘-’即可。
判定方法:如果字符串a的长度大于b的长度,那么不用多说a>b,反之b>a,但是当a=b的时候呢?我们回忆回忆我们之前是不是学过strcmp函数(链接:字符函数,字符串函数),通过这个函数我们可以按位比较ASCII值,通过这种函数我们就可以轻松判定当a和b长度相等时那个大那个小了(一定要在翻转前判定)。
下面我将用代码给大家展示。
#include <stdio.h>
#include<string.h>
void my_reverse(char* arr, int len)//简单的翻转函数
{
for (int i = 0; i < len - 1; i++, len--)
{
char temp = arr[i];
arr[i] = arr[len - 1];
arr[len - 1] = temp;
}
}
void print_sub(int len, char* arr1, char* arr2)
{
for (int i = 0; i < len; i++)
{
if(arr2[i]!='\0')//如果该位置arr2[i]为\0则不需要减去'0'
arr2[i] -= '0';
arr1[i] -= arr2[i];
if (arr1[i] < '0')
{
arr1[i + 1] -= 1;
arr1[i] += 10;
}
}
while (arr1[len - 1] == '0')//10001-10000的话会输出00001为了输出1我们要改变len的大小
len--;
for(int i = len-1;i>=0;i--)
printf("%c", arr1[i]);
if (len < 1)printf("0");//如果答案为0的时候len为0所以这是需要我们手动输入0
}
int main()
{
char arra[10100] = { 0 }, arrb[10100] = { 0 };//分别储存a,b的值
scanf("%s %s", arra, arrb);
int lena = strlen(arra);//计算a和b的长度
int lenb = strlen(arrb);
if(lena == lenb)//我们的目的是让大的减去小的,所以要分情况讨论
{
if (strcmp(arra, arrb) >= 0)
{
my_reverse(arra, lena);//将a和b进行翻转方便进行减法运算
my_reverse(arrb, lenb);
print_sub(lena, arra, arrb);
return 0;
}
else// 如果b>a, a-b=-(b-a)
{
printf("-");//打印个负号
my_reverse(arra, lena);
my_reverse(arrb, lenb);
print_sub(lenb, arrb, arra);
return 0;
}
}
my_reverse(arra, lena);
my_reverse(arrb, lenb);
if (lena > lenb)
{
print_sub(lena, arra, arrb);
}
else if (lena < lenb)// 如果b>a, a-b=-(b-a)
{
printf("-");//打印个负号
print_sub(lenb, arrb, arra);
}
return 0;
}
我们写完代码后可以去洛谷 p2142题(高精度减法)进行检测,看自己是否出现错误。
3,尾声
关于高精度乘法和高精度除法我们放到下一篇博客,如果觉得博主讲的不错,请一定要记得给博主点个关注,点个赞,最好再点个收藏(嘻嘻~)。那么我们下期再见吧!