[位运算] 64位整数乘法(mod 一个数)

Posted fj-linhua

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[位运算] 64位整数乘法(mod 一个数)相关的知识,希望对你有一定的参考价值。

64位整数乘法

  在部分题目中可能涉及到长整数(long long)的相关计算,可当我们需要将两个长整数相乘时有可能出现溢出的情况,这时候通常需要进行高精度计算,可如果我们需要将两个长整数相乘并 mod 一个数时高精度计算也就不太方便了,这时我们需要一个优秀的算法让我们快速的计算出类似 a×b mod c 的数值

[算法描述(1)]

  我们用快速幂的思想,将b用二进制表示

b=ck-12k-1+ck-22k-2+…+c020

  那么:

 a×b=a×(ck-12k-1+ck-22k-2+…+c020)=a×ck-1×2k-1+a×ck-2×2k-2+…+a×c0×20

  又

a×2i=(a×2i-1)×2

  于是我们可以递推地计算出a×2i并且每次计算把答案加入ans中与快速幂不同的是ans的初始化并不是赋值为1而是清0.时间复杂度为O(log2 b).

  在此基础上我们考虑如果a,b是负数那怎么办呢?为了解决这个问题我们考虑打一个标记w,我们将w的初始值赋值为1,如果a,b的值是负数的话就把w值取w=-w(a,b均做一次判断),我们把返回ans×w即可.

  如果b的值远大于a时O(log2 b)这个时间复杂度相对于O(log2 a)而言就不是那么优秀了,于是我们可以进一步优化,如果a比b的数值小的话就交换a和b的数值,那么这个时间复杂度最终为O(log2 min(a,b))当然如果a,b均大于c时可以实现对a,b mod c进一步优化时间复杂度

[代码(1)]

 

/*
    Name: Multiplication 
    Author: FZSZ-LinHua
    Date: 2018 06 07
    Time complexity: O(log min(a,b))
    Algorithm: Binary calculation 
*/
# include "iostream"
# include "cstdio"

using namespace std;

long long mul(long long x,long long y,long long z){    //计算x*y mod z的数值 
    long long ans=0;
    int w=1;
    if(y<0){    //如果y<0那么标记一下,y取绝对值 
        w=-w;
        y=-y; 
    }
    if(x<0){    //如果x<0那么标记一下,x取绝对值 
        w=-w;
        x=-x; 
    }
    if(x<y){    //如果x比y小那么交换x,y 
        swap(x,y); 
    } 
    while(y){
        if(y&1){    //如果y的i位不为0就加入答案中 
            ans=(ans+x)%z; 
        }
        x=(x*2)%z;    //递推计算a^2i 
        y>>=1;     //舍弃最低位 
    }
    return w*ans;//返回答案 
}

int main(){
    long long a,b,c; 
    scanf("%lld%lld%lld",&a,&b,&c);
    printf("%lld",mul(a,b,c));
    return 0; 
} 

 [算法描述(2)]

  对于上述算法我们思考能不能用更短的时间内算出a×b mod c的数值呢?我们发现一个式子

a×b mod c=a×b-[a×b/c]×c([x]表示x下取整)

  我们可以先处理除[a×b/c]×c的数值,算ans时将a×b减去该数值即可,注意计算出的ans值可能为负数也可能大于c所以我们需要对ans加上c再mod c及(ans+c) mod c

[代码(2)]

/*
    Name: Multiplication 
    Author: FZSZ-LinHua
    Date: 2018 06 07
    Time complexity: O(1)
    Algorithm: Brute-force 
*/
# include "iostream"
# include "cstdio"

using namespace std;

long long mul(long long x,long long y,long long z){    //计算x*y mod z的数值 
    long long a=(long double) x*y/z; 
    long long ans=x*y-a*z;
    ans=(ans+z)%z; 
    return ans;
}

int main(){
    long long a,b,c; 
    scanf("%lld%lld%lld",&a,&b,&c);
    printf("%lld",mul(a,b,c));
    return 0; 
} 

 

以上是关于[位运算] 64位整数乘法(mod 一个数)的主要内容,如果未能解决你的问题,请参考以下文章

64位整数乘法讲解-And-AcWing-90. 64位整数乘法

64位整数乘法讲解-And-AcWing-90. 64位整数乘法-方法二

64位整数乘法讲解-And-AcWing-90. 64位整数乘法-《算法竞赛进阶指南》

64位整数乘法讲解-And-AcWing-90. 64位整数乘法-方法二-《算法竞赛进阶指南》

90. 64位整数乘法位运算

ACwing90 64位整数乘法 大数乘法取模