关于高精度计算

我又来啦!!!
今天学了高精(别问我,我不会python),为了别让我的脑子忘了,还是记录一下吧

 首先,要明确高精度是啥??为啥要用高精度??高精能解决啥问题??

其实,不难理解,高精度算法,属于处理大数字的数学计算方法。在一般的科学计算中,会经常要求算到 小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为 高精度数。也只有用高精度才能解决超级大的数的运算;

那么我们进入正题,关于高精度的实现:

首先说说他的思想吧,其实就是把我们因太大而无法处理的数字变成字符数组(串),通过相同位运算的思想记录每一位,判断是否要进位后输出进位后输出。

我们分为以下几种情况讨论:1.高精+高精,2.高精-高精,3.高精*单精,4.高精*高精;(5.高精除法)

 

一、关于高精加高精

首先输入输出,就是用字符数组(个人偏好)把每一位数字记录下来,输出也差不过,就是再把倒序输入的在倒序输出就可以了

 1 #include<iostream>
 2 #include<algorithm>
 3 using namespace std;
 4 char a[...];
 5 string s;
 6 int main()
 7 {
 8     cin>>s;
 9     int len=s.length();
10     for(int i=0;i<len;i++)
11     {
12         a[i]=s[len-1-i]-'0';//a数组记录下这个高精数,这里要用倒序存储,便于以后关于进位等问题 
13     }
14 }

那我们可以开始将两数(组)相加了,这里倒序还有个好处,就是方便排位子,这样个位就能跟另一个数的个位相加,也就是对应数位就能对应相加了。

其实也就是这样的

 a[7] a[6] a[5] a[4] a[3] a[2] a[1] a[0]

+  0   0    b[5] b[4] b[3] b[2] b[1] b[0]

————————————————————

   c[7] c[6] c[5] c[4] c[3] c[2] c[1] c[0]

然而,光这样肯定是不行的,肯定还会有进位的问题,那我们怎么解决呢?

那我们就逢十进一呗(说了好像没说),其实就是让a[i+1]=a[i+1]+a[i]/10  ,  a[i]=a[i]%10

还有一个问题,就是如果最后一位也要进位(也可能不进位)咋办?我只要判断最前面的数字是不是零,如果不是(也就是1),那就再加一位数字,具体代码如下

 1 #include<iostream>
 2 #include<cstring>
 3 #define ll long long 
 4 using namespace std;
 5 ll a[...],b[...],c[...];
 6 int main()
 7 {
 8     string a1,b1;
 9     cin>>a1>>b1;//cin只读一行
10     ll la=a1.length(),lb=b1.length();
11     for(ll i=0;i<la;i++)
12     {
13         a[i]=a1[la-1-i]-'0';//倒序输入 
14     }
15     for(ll i=0;i<lb;i++)
16     {
17         b[i]=b1[lb-1-i]-'0';//倒序输入 
18     }
19     ll lc=la>lb? la:lb;//最后的结果长度就为lc
20     for(int i=0;i<lc;i++)
21     {
22         c[i]=a[i]+b[i];
23     } 
24     for(int i=0;i<lc;i++)
25     {
26         c[i+1]=c[i+1]+c[i]/10;
27         c[i]=c[i]%10;
28     }
29     if(c[lc]>0) lc++;//如果最后一位也要进位,就再加一位
30     //不在第18行就加一位是因为我不知道是否要进位 
31     for(int i=lc-1;i>=0;i--)//因为倒序输入,所以倒序输出 
32     {
33         cout<<c[i];
34     } 
35     return 036 } 

 

做一道题练练?

关于斐波那契数列,输入n,输出第n项的值(3<=n<=1000)

这一看就要用高精度·,毕竟第49项就已经有7778742049那么大了

#include<iostream>  
#include<cstring>  
using namespace std;
int a[1001],b[1001],c[1001];
int main()
{        
    int n,la,lb,lc;  
    cin>>n;  
    a[0]=1; la=1;
    b[0]=1; lb=1;
    for(int k=3;k<=n;k++) 
    {
        lc=lb;
        for(int i=0;i<lc;i++)
        {
            c[i]=a[i]+b[i];
        }
        for(int i=0;i<lc;i++) 
        {
            c[i+1]=c[i+1]+c[i]/10; 
            c[i]=c[i]%10;
        }
        if(c[lc]>0) 
        {
            lc++;
        }  
        la=lb;
        lb=lc;
        memcpy(a,b,1000*sizeof(int));//内存拷贝函数
         memcpy(b,c,1000*sizeof(int));//包含在<cstring>
    }
    for(int i=lc-1;i>=0;i--) 
    {
        cout<<c[i];    
    } 
     return 0;
} 

这里,memcpy( a,b,sizeof())相当于b=a :把a的全部都给b。这里相当于fib( )的逐步递推作用

 

二、高精减高精

首先我们还是读入两个数组,值得注意的是,我们尽量让大的减小的(比较方便),如果是小的减大的,我们交换一下值,再加一个负号就好

其实个人看来,高精减和高精加差的不多,就是把进位改成借位就好

怎么借位呢?

我们判断a[i]是否大于b[i](a-b),如果大于,就不用借位,如果小于,我们就向前一位借1,这一位再加10即可,也就是

1 for (int i=0;i<la;i++)
2 {
3      if (a[i]<b[i])
4      {    
5         a[i+1]--;  a[i]+=10;
6     }
7     a[i]=a[i]-b[i];
8 }

还有就是需要把最高位的0去掉,最后输出就是

 1 while (a[la]==0&&la>0) la--;

2 for (int i=la;i>=0;i--) cout<<a[i];  

综合一下,代码如下

 1 #include<iostream>
 2 #include<cstring>
 3 #define ll long long 
 4 using namespace std;
 5 ll a[...],b[...];
 6 int main()
 7 {
 8     string a1,b1;
 9     cin>>a1>>b1;//cin只读一行
10     ll la=a1.length(),lb=b1.length();
11     if(a1==b1)//如果这两个字符串相同 
12     {
13         cout<<0;
14         return 0;
15     }  
16     if(la<lb||la==lb&&a1<b1)//判断谁大谁小并交换 
17     {
18         swap(a1,b1);
19         swap(la,lb);
20         cout<<"-";
21     }
22     for(ll i=0;i<la;i++)
23     {
24         a[i]=a1[la-1-i]-'0';//倒序输入 
25     }
26     for(ll i=0;i<lb;i++)
27     {
28         b[i]=b1[lb-1-i]-'0';//倒序输入 
29     }
30     for (ll i=0;i<la;i++)//不够要借位 
31      {
32           if(a[i]<b[i])
33           {    
34                 a[i+1]--;  
35             a[i]+=10;
36          }
37         a[i]=a[i]-b[i];
38     }
39     while(la>0&&a[la]==0)
40     {
41         la--;//处理前面的0 
42     }
43     for(ll i=la;i>=0;i--)
44     {
45         cout<<a[i]; 
46     }
47     return 048 } 

 

三、高精乘单精

可以简单的想一下小学学过的列式乘法

 其实就是让单精数乘高精数的每一位,并记录下来,最后再进位就好了,值得注意的是,最后一位数字可能会进很多位,所以要用个循环来解决

 

 1 #include<iostream>
 2 #include<cstring>
 3 #define ll long long 
 4 using namespace std;
 5 int main(){
 6     ll la,a[...]={0},m;
 7     int b;
 8     string a1;
 9     cin>>a1>>b;
10     la=a1.length();
11     for(ll i=0;i<la;i++)
12     {
13         a[i]=a1[la-1-i]-'0';
14     }
15     for(ll i=0;i<la;i++)
16     {
17         a[i]=a[i]*b;
18     }
19     for(ll i=0;i<la;i++)
20     {
21         a[i+1]=a[i+1]+a[i]/10;
22         a[i]=a[i]%10;
23     }
24     m=a[la];//我把m作为最高位
25     while(m>0)//处理最后一位的进位问题 
26     {
27         a[la]=m%10;
28         m=m/10;
29         ++la;
30     } 
31     for(ll i=la-1;i>=0;i--)
32     {
33         cout<<a[i];
34     }
35     return 0; 
36 }

 

四、高精乘高精

其实跟单精乘高精思想差不多,我们找出位数小一点的高精数,把它分为多个数字,让他们这些数字挨个相乘,最后再整理一下就OK了

还有一点值得一提的是,两数相乘的位数就是两数的位数之和或再减1

但是,最后的整理工作也是有点繁琐的,因为他们是错位相乘,针对这种情况,我们找到一个规律·

不难发现,错位相乘再相加,同一行的数是有特点的,也就是上面所说的:

c[i+j]+=a[i]*b[i],即a的下标和b的下标之和(即i+j)对应的就是就是我们最后要输出的第几位,也就是c的下标

 1 #include<iostream>
 2 #include<cstring>
 3 #define ll long long 
 4 using namespace std;
 5 int a[...],b[...],c[...];
 6 int main()
 7 {
 8     string a1,b1;
 9     ll la,lb,lc;
10     cin>>a1>>b1;
11     la=a1.length(),lb=b1.length();
12     lc=la+lb;
13     for(ll i=0;i<la;i++)
14     {
15         a[i]=a1[la-1-i]-'0';
16     }
17     for(ll i=0;i<lb;i++)
18     {
19         b[i]=b1[lb-1-i]-'0';
20     }
21     for(ll i=0;i<la;i++)
22     {
23         for(ll j=0;j<lb;j++){
24             c[i+j]+=a[i]+b[j];//有很多种组合方式,把他们加起来 
25         }
26     }
27     for(ll i=0;i<lc;i++)
28     {
29         c[i+1]+=c[i]/10;
30         c[i]=c[i]%10;
31     }
32     if(c[lc-1]==0) lc--;//处理最高位0
33     for(ll i=lc-1;i>=0;i--)
34     {
35         cout<<c[i];
36     }
37     return 0; 
38 }

 

五、高精除

这里有代码(只有代码)可以推导一下(这里只写了高精除以单精)

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 int main()
 6 {
 7     char a1[5000];
 8     int a[5000]={0},c[5000]={0};
 9     long long la,lc,b,r=0,i;
10     cin>>a1>>b;
11     la=strlen(a1);
12     for(i=0;i<la;i++)
13     {
14         a[i]=a1[i]-48;
15     }
16     for(i=0;i<la;i++)
17     
18     {
19         c[i]=(10*r+a[i])/b;
20         r=(r*10+a[i])%b;
21     }
22     lc=0;
23     while(c[lc]==0&&lc<la-1)
24     {
25         lc++;
26     }
27     for(i=lc;i<la;i--)
28     {
29         cout<<c[i];
30     }
31     return 0;
32 }

 

-----“其实只要思想到位了,就不算多难以理解了对吧?”

-----“em...我没有思想,甚至没有脑子.....”

就先讲到这里吧,再见

2022/3/13

posted @ 2022-03-13 11:50  你的小垃圾  阅读(164)  评论(0编辑  收藏  举报