• 大整数乘法(Comba 乘法 (Comba  Multiplication)原理)


    Comba 乘法以(在密码学方面)不太出名的 Paul G. Comba 得名。上面的笔算乘法,虽然比较简单, 但是有个很大的问题:在 O(n^2) 的复杂度上进行计算和向上传递进位,看看前面的那个竖式,每计算一次单精度乘法都要计算和传递进位,这样的话就使得嵌套循环的顺序性很强,难以并行展开和实现。Comba 乘法则无需进行嵌套进位来计算乘法,所以虽然其时间复杂度和基线乘法一样,但是速度会快很多。还是以计算 123 * 456 为例:

                                                                      1            2            3

                                                           x        4             5            6

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

                                                                     6           12          18

                                                        5          10         15

                                           4           8          12

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

                                           4          13          28         27         18

                                           4          13          28         28           8

                                           4          13          30          8     

                                           4          16           0

                                           5          6

                                0         5

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

                                            5           6             0            8             8

                和普通的笔算乘法很类似,只是每一次单精度乘法只是单纯计算乘法,不计算进位,进位留到每一列累加后进行。所以原来需要 n * n 次进位,现在最多只需要 2n 次即可。

                以上就是 Comba 乘法的原理,不过这里有个比较严重的问题:如何保证累加后结果不溢出。上面的例子,假设单精度数 1  位数,双精度是两位数,那万一累加后的结果超过两位数则么办?那没办法,只能用三精度变量了。在大整数算法中,单精度能表示的最大整数是 2^n - 1(n 是单精度变量的比特数),用三个单精度变量 c2,c1,c0 连在一起作为一个三精度变量(高位在左,低位在右),则 c2 || c1 || c0 能表示的最大整数是 2^(3n) - 1,最多能存放 (2^(3n) - 1) / ((2^n - 1)^2) 个单精度乘积结果。当 n = 32 时,能够存放 4294967298 个单精度乘积结果;当 n = 64 时,能够存放约 1.845 * 10^19 个单精度乘积结果,而我一开始规定 bignum 不能超过 25600 个数位,这样使用三精度变量就可以保证累加结果不会溢出了。

                  有了上面的铺垫,下面就把 Comba 乘法的思路列出来:

    1.先将俩个字符数组从后面开始转换为整数数组;

    2.乘以后的数组就是c[i+j]+=a[i]*b[j];

    3.c数组从小到大依次进位

    4.输出,注意c数组是的0是个位,所以从最后一位开始输出,用ok标志不为0的时候开始输出

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<string>
     4 #include<cstring>
     5 using namespace std;
     6 int main()
     7 {
     8     char  a[100],b[100];
     9     cin>>a>>b;
    10     int x[100],y[100],c[20000];
    11     int flag=0;
    12       for(int i=0;i<20000;i++)
    13          c[i]=0;
    14     for(int i=strlen(a)-1;i>=0;i--)
    15           x[flag++]=a[i]-'0';
    16           int key=0;
    17           for(int i=strlen(b)-1;i>=0;i--)
    18             y[key++]=b[i]-'0';
    19           for(int i=0;i<flag;i++)
    20                 for(int j=0;j<key;j++)
    21                      c[i+j]+=x[i]*y[j];
    22 
    23 
    24                     for(int i=0;i<20000;i++)
    25                     {
    26                         if(c[i]>=10)
    27                         {
    28                             c[i+1]+=c[i]/10;
    29                             c[i]%=10;
    30 
    31                         }
    32                         }
    33                     int ok=0;
    34                     for(int i=20000-1;i>=0;i--)
    35                     {
    36                         if(ok) cout<<c[i];
    37                         else if(c[i])
    38                         {
    39                             cout<<c[i];
    40                             ok=1;
    41 
    42                         }
    43 
    44 
    45             }
    46 
    47     return 0;
    48 
    49 
    50 
    51 
    52 }
  • 相关阅读:
    当别人疑惑时你坚定
    如何设置mvc的role和user
    在项目中添加引用的意思
    vs的使用技巧
    无法删除表实体的问题
    JavaScriptSerializer类
    统计代码行数&&遍历jQuery
    远程调用
    select、验证
    委托和事件的区别
  • 原文地址:https://www.cnblogs.com/blvt/p/7216745.html
Copyright © 2020-2023  润新知