知识:高精度加法和减法

嗯...  首先让我们引入高精度这个东西....
相信大家都会做A+B Problem 这道题....输出的是A+B 的值....
可你想过没有,如果A= 5983461827658923256597314923593449492545242655621498167329758256231975822594359252779832914372582828292235591346798922923,
B = 9382872892382859234389628259232359438768953797679368296159683689865328523725925829753298653219197389235498228659659373291973652564256594,
而这时,所有的类型都无法存储A和B这两个数....而这时,高精度就要出马了...(附图关于数据类型范围....

知识:高精度加法和减法


这里首先讲的是高精度的加法。下面是一个伪代码,主要表达了高精度加法的主要流程:

read();//读入两个大整数; 
calsum();//求和; 
print();//输出结果;

 Question 1 :
这么大的数,如何进行读入?
Answer   1:
当输入的数很大时,可采用字符串方式接收。输入要符合整数的输入规则:连续输入每位数字,中间无空格。


在这里会牵扯到另一部分的知识——字符串...其实字符串还是比较常用的...
下面就简单提几方面:

Part 1:
字符串定义方式:
string s; // 直接定义
char s[1007];//用一个字符数组模拟字符串,这种的灵活性与速度上有优势
不同方式定义的字符串,对应的函数也不同
如  string s;   len = s.length();
而  char s[1007]; len = strlen(s);

Part  2:
字符串的读入:
这里主要介绍三种方式:
1. cin 

string s1,s2;
cin>>s1>>s2;
int lena = s1.length();
int lenb = s2.length();
  
cout<<s1<<" "<<s2<<endl;
cout<<lena<<" "<<lenb;

2. scanf

char s1[1010],s2[1010];
int main()
{
     scanf("%s%s",s1,s2); // scanf("%s%s",   &s1,   &s2);&可省略
     int lena=strlen(s1); //strlen()函数需要头文件cstring
     int lenb=strlen(s2);
      
     cout<<s1<<" "<<s2<<endl;
     cout<<lena<<" "<<lenb;
}

3. gets

char s1[1010],s2[1010];
gets(s1);
gets(s2);
lena=strlen(s1);
lenb=strlen(s2);

注意:
scanf、cin遇空格或回车符则认为当前字符串结束
gets遇回车符则认为当前字符串结束

Question  2:
我们将读入的数作为字符串接收了进来,可是怎么进行加减乘除等数学运算呢?
Answer   2:
拆成一位一位的数字,把它们存在一个数组中,一个数组元素表示一位数字……解释:“拆”


例如:

知识:高精度加法和减法

详细过程:——字符串读入,数组保存(见代码
//利用字符串函数和操作运算,将每一位数取出,存入数组中。 //假设已经利用字符串s读取数据 lena=s.length(); //用lena存放字符串s的位数 for(i=1;i<=lena;i++) a[i]=s[lena-i] -'0'; //将数串s转换为数组a,注意:倒序存储


 

知识:高精度加法和减法

解释倒序保存的原因:
在平常,数字从左到右依次为从高位到低位....可这里却与日常的习惯相反。因为在存储时我们首先能确定的就是最低位,所以设它为第一位,而高位无法确定,因为在存储之前求出字符串的长度比较麻烦,所以我们用下标较大的数组存储高位,因为它的最高位无法确定....

Question  3:
两个高精度数已经分别保存在数组a和b中,下一步,应该如何求和?
Answer  3:
用到了小学所学的”竖式计算“的思想:

知识:高精度加法和减法


运算的次数为:max(lena, lenb);


程序实现:
方法一:
模拟手工计算,设置一个进位变量m,但是此方式比较麻烦:

for(int i=1;i<=lena;i++)
    a[i]=s1[lena-i]-48;//由字符转向真正意义的数字 ,并且为倒序
for (int i=1;i<=lenb;i++)
    b[i]=s2[lenb-i]-48;//同上
lenc=max(lena,lenb);
for(int i=1;i<=lenc;i++)
{
    c[i]=(m+a[i]+b[i])%10;
    m=(m+a[i]+b[i])/10;//进位
}
if(m) {//判断最高位是否需要进位
    lenc++;
    c[lenc]=1;
}

方法二:
先计算,最后处理进位,比方法一要简单:

for (int i=1;i<=lena;i++)  
     a[i]=a[i]+b[i]; //直接加在a数组中 
for (int i=1;i<=lena;i++)
{
     a[i+1]=a[i+1]+a[i]/10;//进位 
     a[i]=a[i]%10;//保留 
}
if (a[lena+1]) lena++;//特判

最后的问题:
——运算结果的输出:

for (i=lenc;i>=1;i--) 
         printf("%d",c[i]);   //输出结果
printf("\n");
  
==============================
  
for (i=lenc;i>=1;i--) 
         cout<<c[i];   //输出结果
cout<<endl;

好的,关于高精度的每一个板块已经说明清楚了,下面我们来看一下完整的高精度运算:
(模板============================================================

#include<bits/stdc++.h> 
using namespace std;
  
int a[506],b[506];
int lena,lenb,lenc;
int m;
string a1,b1;
  
int main(){
    cin>>a1>>b1;
    lena = a1.size();
    lenb = b1.size();
    for (int i = 0; i < lena; i++){
        a[lena - i - 1] = a1[i] -'0';
    }
    for(int i = 0; i < lenb; i++){
        b[lenb - i - 1] = b1[i] - '0';
    }
    lenc = max( lena,lenb );
    for (int i=0;i<lenc;i++)  
        a[i]+=b[i]; //直接加在a数组中 
    for (int i=0;i<lenc;i++)
    {
        a[i+1]+=a[i]/10;//进位 
        a[i]%=10;//保留
    }
    if (a[lenc]) lenc++;//特判
    for (i=lenc-1;i>=0;i--)
         printf("%d",c[i]);   //输出结果
    return 0;
}

上一篇:力扣-面试题刷题第一天


下一篇:年初啃完这7套Java面试题,年后阿里P7稳了,收藏夹吃灰