• 高精度算法之大数运算


    思想:

    先用字符串来读入大整数,然后用数组来存储大整数。与上一篇的所讲思路不同的是,这次是数组的每一个元素对应大整数的一个数,从而模拟手算过程。

    主要实现思路与手算无太大差别。主要是一些细节上。

    统一做个说明:模拟大数的数组的第零个元素保存的是数字个数(不包括第零个元素),而且数组从1到尾分别存大数的低位到高位,刚好相反。

    在运算过程中的对齐操作全以此为标准。

    读入时统一处理:

     1 memset(a,0,sizeof(a));
     2     memset(b,0,sizeof(b));
     3     cin >> s >> t;//输入两个大数到字符串中
     4     a[0] = s.length();//存储字符串s元素的个数,即大数a的位数
     5     for(int i = 1;i<=a[0];i++)//并转化为整数存储在数组a中的对应位置
     6     {
     7         a[i] = s[a[0]-i]-'0';
     8     }
     9     b[0] = t.length();//存储字符串t的个数,即大数b的位数
    10     for(int i = 1;i<=b[0];i++)//并转化为整数存储在数组b中的对应位置
    11     {
    12         b[i] = t[b[0]-i]-'0';
    13     }

    高精度加法:

     1 void add(int* a,int* b)
     2 {
     3     len = max(a[0],b[0]);
     4     for(int i = 1;i<=len;i++)
     5     {
     6         a[i] = a[i]+b[i];
     7         a[i+1] += a[i]/10;//进位
     8         a[i] %= 10;
     9     }
    10     len++;//去除前导零
    11     while(a[len]==0&&len>1)
    12     {
    13         len--;
    14     }
    15     for(int i = len;i>0;i--)
    16     {
    17         cout << a[i];
    18     }
    19     cout << endl;
    20 }

    高精度减法:

    减法的特别之处在于两个数的大小不确定,那我们就先比较两个数的大小,保证用大的数减去小的数,结果分类看是否加负号。

     1 int larger(string s,string t) //看s是否>=t
     2 {
     3     if(s.length()!=t.length())
     4     {
     5         return s.length()>t.length();//长度不同长的大
     6     }
     7     for(int i = 0;i<s.length();i++)
     8     {
     9         if(s[i]!=t[i])
    10         {
    11             return s[i]>t[i];//长度相同,一位一位比较大小
    12         }
    13     }
    14     return 1;
    15 }
    16 void sub(int* a,int* b,string s,string t) //a-b,s对应a,t对应b
    17 {
    18     if(larger(s,t))
    19     {
    20         for(int i = 1;i<=a[0];i++)
    21         {
    22             a[i] -= b[i];
    23             if(a[i]<0)
    24             {
    25                 a[i+1]--;//借位
    26                 a[i] += 10;
    27             }
    28         }
    29         a[0]++;//去除前导零
    30         while(a[a[0]]==0&&a[0]>1)
    31         {
    32             a[0]--;
    33         }
    34         for(int i = a[0];i>0;i--)
    35         {
    36             cout << a[i];
    37         }
    38         cout << endl;
    39     }
    40     else
    41     {
    42         for(int i = 1;i<=b[0];i++)
    43         {
    44             b[i] -= a[i];
    45             if(b[i]<0)
    46             {
    47                 b[i+1]--;//借位
    48                 b[i]+=10;
    49             }
    50         }
    51         b[0]++;//去除前导零
    52         while(b[b[0]]==0&&b[0]>0)
    53         {
    54             b[0]--;
    55         }
    56         cout << "-";
    57         for(int i = b[0];i>0;i--)
    58         {
    59             cout << b[i];
    60         }
    61         cout << endl;
    62     }
    63 }

    高精度乘法:

    注意了,因为模拟手算的过程,为了方便,这里用了零一个数组c来存乘法的结果,看一下c在运算过程中是怎么存储数到对应位置的。

      1 2 3                                 3 2 1

      * 2 3                                 2 3 0

      -------                               ------------

      3 6 9                                 6 4 2

    24 6                                    9 6 3

    (此为正常手算)因为是倒着存储的,数组c每次存进数的位置应该往后移

     1 void mul(int* a,int* b)
     2 {
     3     memset(c,0,sizeof(c));
     4     for(int i = 1;i<=a[0];i++)
     5     {
     6         for(int j = 1;j<=b[0];j++)
     7         {
     8             c[i+j-1] = a[i]*b[j];//a中每一个数分别乘以b的每一个数后加到对应的c的位置上
     9             c[i+j] = c[i+j-1]/10;//进位
    10             c[i+j-1] %= 10;//余下来的数
    11         }
    12     }
    13     c[0] = a[0]+b[0]+1;//c[0]中存放数字的位数
    14     while(c[c[0]]==0&&c[0]>1)//去除前导零,同时让c正确统计c的数字的位数
    15     {
    16         c[0]--;
    17     }
    18     for(int i = c[0];i>0;i--)
    19     {
    20         cout << c[i];
    21     }
    22     cout << endl;
    23 }

    高精度除法:

    分为高精度除以低精度和高精度除以高精度

    第一种:

    直接用每一位加上上一项余数的10倍的和除以除数即可得最终结果,注意要去掉前导零。

     1 void div1(int* a,long long b)//高精除以低精
     2 {
     3     int lena,lenc;
     4     int x = 0;//x为前一次运算的余数
     5     memset(c,0,sizeof(c));
     6     for(int i = a[0];i>0;i--)//注意顺序从第一位开始计算
     7     {
     8         c[i] = (10*x+a[i])/b;//这一位加上前一次计算的余数
     9         x = (10*x+a[i])%b;
    10     }
    11     lenc = 1;
    12     while(c[lenc]==0&&lenc<a[0])//出去前导零
    13     {
    14         lenc++;
    15     }
    16     for(int i = lenc;i<=a[0];i++)
    17     {
    18         cout << c[i];
    19     }
    20     cout << endl;
    21 }

    第二种:

    不再直接每一位除,要找到刚开始除的位置,在哪呢?(a[0]-b[0]+1)

    比如1 2 3 4 5除以1 2 3 a[0]-b[0]+1=3

    5 4 3 2 1

      ↑此为开始除的位置

    还要注意不能直接除以除数,因为除数也是高精度,就用减法代模拟除法,细节见代码:

     1 int cmp(int* a,int* b)//比较a是不是大于等于b
     2 {
     3     if(a[0]!=b[0])
     4     {
     5         return a[0]>b[0];
     6     }
     7     for(int i = a[0];i>0;i--)
     8     {
     9         if(a[i]!=b[i])
    10         {
    11             return a[i]>b[i];
    12         }
    13     }
    14     return 1;
    15 }
    16 void sub(int* a,int *b)//用a减去b
    17 {
    18     for(int i = 1;i<=a[0];i++)
    19     {
    20         a[i]-=b[i];
    21         if(a[i]<0)
    22         {
    23             a[i]+=10;
    24             a[i+1]--;
    25         }
    26     }
    27     a[0]++;
    28     while(a[0]>1&&a[a[0]]==0)
    29     {
    30         a[0]--;
    31     }
    32     return;
    33 }
    34 void div2(int* a,int* b)//高精除以高精
    35 {
    36     int temp[max_n];
    37     c[0] = a[0]-b[0]+1;//c[0]的位置为a比b多的数+1的地方
    38     for(int i = c[0]; i>0; i--)
    39     {
    40         memset(temp,0,sizeof(temp));//temp存储被除数
    41         for(int j = 1; j<=b[0]; j++)
    42         {
    43             temp[i+j-1] = b[j];//对应从i开始的地方,复制数组b到temp中
    44         }
    45         temp[0] = b[0]+i-1;
    46         while(cmp(a,temp))//用减法模拟
    47         {
    48             /*cout << "a" << endl;
    49             for(int i = 1;i<=a[0];i++)
    50             {
    51                 cout << a[i];
    52             }
    53             cout << endl;*/
    54             c[i]++;
    55             sub(a,temp);
    56         }
    57     }
    58     c[0]++;
    59     while(c[0]>1&&c[c[0]]==0)//删除前导零
    60     {
    61         c[0]--;
    62     }
    63     cout << "商为:";
    64     for(int i = c[0]; i>0; i--)
    65     {
    66         cout << c[i];
    67     }
    68     cout << endl;
    69     cout << "余数为:";
    70     if(a[0]==0)
    71     {
    72         cout << 0 << endl;
    73     }
    74     else
    75     {
    76         for(int i = a[0]; i>0; i--)
    77         {
    78             cout << a[i];
    79         }
    80         cout << endl;
    81     }
    82 }

    以上就是高精度算法的大数运算,不失为一个好模板,只是相应的输出操作有可能会改变。

    代码汇总:

      1 #include <iostream>
      2 #include <string>
      3 #include <memory.h>
      4 #define max_n 250
      5 using namespace std;
      6 int a[max_n];
      7 int b[max_n];
      8 int c[max_n<<1];
      9 string s,t;
     10 int len;
     11 void add(int* a,int* b)
     12 {
     13     len = max(a[0],b[0]);
     14     for(int i = 1;i<=len;i++)
     15     {
     16         a[i] = a[i]+b[i];
     17         a[i+1] += a[i]/10;//进位
     18         a[i] %= 10;
     19     }
     20     len++;//去除前导零
     21     while(a[len]==0&&len>1)
     22     {
     23         len--;
     24     }
     25     for(int i = len;i>0;i--)
     26     {
     27         cout << a[i];
     28     }
     29     cout << endl;
     30 }
     31 int larger(string s,string t) //看s是否>=t
     32 {
     33     if(s.length()!=t.length())
     34     {
     35         return s.length()>t.length();//长度不同长的大
     36     }
     37     for(int i = 0;i<s.length();i++)
     38     {
     39         if(s[i]!=t[i])
     40         {
     41             return s[i]>t[i];//长度相同,一位一位比较大小
     42         }
     43     }
     44     return 1;
     45 }
     46 void sub(int* a,int* b,string s,string t) //a-b,s对应a,t对应b
     47 {
     48     if(larger(s,t))
     49     {
     50         for(int i = 1;i<=a[0];i++)
     51         {
     52             a[i] -= b[i];
     53             if(a[i]<0)
     54             {
     55                 a[i+1]--;//借位
     56                 a[i] += 10;
     57             }
     58         }
     59         a[0]++;//去除前导零
     60         while(a[a[0]]==0&&a[0]>1)
     61         {
     62             a[0]--;
     63         }
     64         for(int i = a[0];i>0;i--)
     65         {
     66             cout << a[i];
     67         }
     68         cout << endl;
     69     }
     70     else
     71     {
     72         for(int i = 1;i<=b[0];i++)
     73         {
     74             b[i] -= a[i];
     75             if(b[i]<0)
     76             {
     77                 b[i+1]--;//借位
     78                 b[i]+=10;
     79             }
     80         }
     81         b[0]++;//去除前导零
     82         while(b[b[0]]==0&&b[0]>0)
     83         {
     84             b[0]--;
     85         }
     86         cout << "-";
     87         for(int i = b[0];i>0;i--)
     88         {
     89             cout << b[i];
     90         }
     91         cout << endl;
     92     }
     93 }
     94 void mul(int* a,int* b)
     95 {
     96     memset(c,0,sizeof(c));
     97     for(int i = 1;i<=a[0];i++)
     98     {
     99         for(int j = 1;j<=b[0];j++)
    100         {
    101             c[i+j-1] = a[i]*b[j];//a中每一个数分别乘以b的每一个数后加到对应的c的位置上
    102             c[i+j] = c[i+j-1]/10;//进位
    103             c[i+j-1] %= 10;//余下来的数
    104         }
    105     }
    106     c[0] = a[0]+b[0]+1;//c[0]中存放数字的位数
    107     while(c[c[0]]==0&&c[0]>1)//去除前导零,同时让c正确统计c的数字的位数
    108     {
    109         c[0]--;
    110     }
    111     for(int i = c[0];i>0;i--)
    112     {
    113         cout << c[i];
    114     }
    115     cout << endl;
    116 }
    117 void div1(int* a,long long b)//高精除以低精
    118 {
    119     int lena,lenc;
    120     int x = 0;//x为前一次运算的余数
    121     memset(c,0,sizeof(c));
    122     for(int i = a[0];i>0;i--)//注意顺序从第一位开始计算
    123     {
    124         c[i] = (10*x+a[i])/b;//这一位加上前一次计算的余数
    125         x = (10*x+a[i])%b;
    126     }
    127     lenc = 1;
    128     while(c[lenc]==0&&lenc<a[0])//出去前导零
    129     {
    130         lenc++;
    131     }
    132     for(int i = lenc;i<=a[0];i++)
    133     {
    134         cout << c[i];
    135     }
    136     cout << endl;
    137 }
    138 int cmp(int* a,int* b)//比较a是不是大于等于b
    139 {
    140     if(a[0]!=b[0])
    141     {
    142         return a[0]>b[0];
    143     }
    144     for(int i = a[0];i>0;i--)
    145     {
    146         if(a[i]!=b[i])
    147         {
    148             return a[i]>b[i];
    149         }
    150     }
    151     return 1;
    152 }
    153 void sub(int* a,int *b)//用a减去b
    154 {
    155     for(int i = 1;i<=a[0];i++)
    156     {
    157         a[i]-=b[i];
    158         if(a[i]<0)
    159         {
    160             a[i]+=10;
    161             a[i+1]--;
    162         }
    163     }
    164     a[0]++;
    165     while(a[0]>1&&a[a[0]]==0)
    166     {
    167         a[0]--;
    168     }
    169     return;
    170 }
    171 void div2(int* a,int* b)//高精除以高精
    172 {
    173     int temp[max_n];
    174     c[0] = a[0]-b[0]+1;//c[0]的位置为a比b多的数+1的地方
    175     for(int i = c[0]; i>0; i--)
    176     {
    177         memset(temp,0,sizeof(temp));//temp存储被除数
    178         for(int j = 1; j<=b[0]; j++)
    179         {
    180             temp[i+j-1] = b[j];//对应从i开始的地方,复制数组b到temp中
    181         }
    182         temp[0] = b[0]+i-1;
    183         while(cmp(a,temp))//用减法模拟
    184         {
    185             /*cout << "a" << endl;
    186             for(int i = 1;i<=a[0];i++)
    187             {
    188                 cout << a[i];
    189             }
    190             cout << endl;*/
    191             c[i]++;
    192             sub(a,temp);
    193         }
    194     }
    195     c[0]++;
    196     while(c[0]>1&&c[c[0]]==0)//删除前导零
    197     {
    198         c[0]--;
    199     }
    200     cout << "商为:";
    201     for(int i = c[0]; i>0; i--)
    202     {
    203         cout << c[i];
    204     }
    205     cout << endl;
    206     cout << "余数为:";
    207     if(a[0]==0)
    208     {
    209         cout << 0 << endl;
    210     }
    211     else
    212     {
    213         for(int i = a[0]; i>0; i--)
    214         {
    215             cout << a[i];
    216         }
    217         cout << endl;
    218     }
    219 }
    220 int main()
    221 {
    222     memset(a,0,sizeof(a));
    223     memset(b,0,sizeof(b));
    224     cin >> s >> t;//输入两个大数到字符串中
    225     a[0] = s.length();//存储字符串s元素的个数,即大数a的位数
    226     for(int i = 1;i<=a[0];i++)//并转化为整数存储在数组a中的对应位置
    227     {
    228         a[i] = s[a[0]-i]-'0';
    229     }
    230     b[0] = t.length();//存储字符串t的个数,即大数b的位数
    231     for(int i = 1;i<=b[0];i++)//并转化为整数存储在数组b中的对应位置
    232     {
    233         b[i] = t[b[0]-i]-'0';
    234     }
    235     return 0;
    236 }
    View Code

    参考文章:

    这里有讲得很清楚的高精度四则运算的博客:

    老樊Lu码,高精度加、减、乘、除算法实现详解,https://blog.csdn.net/fanyun_01/article/details/79967170

  • 相关阅读:
    如何禁止用户直接对TextBox进行数据粘贴?(ASP.NET WEB开发)
    jquery过滤选择器前加空格与不加空格的区别(转)
    linux设置ip.dns.gateway
    Adobe Fireworks CS4 序列号(注册码)
    AS3清空数组的四种方法
    Flash中用AS3做的游戏,导出apk安装到手机上滤镜效果出不来为什么?
    用AS3清空容器下所有子显示对象
    对Linux进程的理解
    C++基础
    虚拟机三种网络模式(hostonly、Bridged、NAT)
  • 原文地址:https://www.cnblogs.com/zhanhonhao/p/11255660.html
Copyright © 2020-2023  润新知