📜  在大模下将大整数相乘

📅  最后修改于: 2021-04-23 06:31:06             🧑  作者: Mango

给定整数a,b,m。查找(a * b)mod m,其中a,b可能很大,并且它们的直接相乘可能会导致溢出。但是,它们小于允许的long long long int最大值的一半。

例子:

Input: a = 426, b = 964, m = 235
Output: 119
Explanation: (426 * 964) % 235  
            = 410664 % 235
            = 119

Input: a = 10123465234878998, 
       b = 65746311545646431
       m = 10005412336548794 
Output: 4652135769797794

天真的方法是使用任意精度的数据类型,例如Python的int或Java的Biginteger类。但是这种方法将不会有成果,因为将字符串内部转换为int然后执行操作将导致二进制数系统中加法和乘法运算的速度变慢。

有效的解决方案:由于a和b可能是非常大的数字,所以如果我们尝试直接相乘,则肯定会溢出。因此,我们使用乘法的基本方法,即

a * b = a + a +…+ a(b次)
因此我们可以轻松计算加法的值(模m下),而无需任何
在计算中溢出。但是,如果我们试图反复加起来价值b乘以那么它肯定会超时值较大的B的,因为这种方法的时间复杂度将成为O(B)。

因此,我们以一种更简单的方式划分了上述重复步骤,即

If b is even then 
  a * b = 2 * a * (b / 2), 
otherwise 
  a * b = a + a * (b - 1)

下面是描述以上解释的方法:

C++
// C++ program of finding modulo multiplication
#include
  
using namespace std;
  
// Returns (a * b) % mod
long long moduloMultiplication(long long a,
                            long long b,
                            long long mod)
{
    long long res = 0; // Initialize result
  
    // Update a if it is more than
    // or equal to mod
    a %= mod;
  
    while (b)
    {
        // If b is odd, add a with result
        if (b & 1)
            res = (res + a) % mod;
  
        // Here we assume that doing 2*a
        // doesn't cause overflow
        a = (2 * a) % mod;
  
        b >>= 1; // b = b / 2
    }
  
    return res;
}
  
// Driver program
int main()
{
    long long a = 10123465234878998;
    long long b = 65746311545646431;
    long long m = 10005412336548794;
    cout << moduloMultiplication(a, b, m);
    return 0;
}
  
// This code is contributed 
// by Akanksha Rai


C
// C program of finding modulo multiplication
#include
  
// Returns (a * b) % mod
long long moduloMultiplication(long long a,
                               long long b,
                               long long mod)
{
    long long res = 0;  // Initialize result
  
    // Update a if it is more than
    // or equal to mod
    a %= mod;
  
    while (b)
    {
        // If b is odd, add a with result
        if (b & 1)
            res = (res + a) % mod;
  
        // Here we assume that doing 2*a
        // doesn't cause overflow
        a = (2 * a) % mod;
  
        b >>= 1;  // b = b / 2
    }
  
    return res;
}
  
// Driver program
int main()
{
    long long a = 10123465234878998;
    long long b = 65746311545646431;
    long long m = 10005412336548794;
    printf("%lld", moduloMultiplication(a, b, m));
    return 0;
}


Java
// Java program of finding modulo multiplication 
class GFG 
{
  
    // Returns (a * b) % mod 
    static long moduloMultiplication(long a,
                            long b, long mod)
    {
          
        // Initialize result
        long res = 0;  
  
        // Update a if it is more than 
        // or equal to mod 
        a %= mod;
  
        while (b > 0) 
        {
              
            // If b is odd, add a with result 
            if ((b & 1) > 0) 
            {
                res = (res + a) % mod;
            }
  
            // Here we assume that doing 2*a 
            // doesn't cause overflow 
            a = (2 * a) % mod;
  
            b >>= 1; // b = b / 2 
        }
        return res;
    }
  
    // Driver code 
    public static void main(String[] args) 
    {
        long a = 10123465234878998L;
        long b = 65746311545646431L;
        long m = 10005412336548794L;
        System.out.print(moduloMultiplication(a, b, m));
    }
} 
  
// This code is contributed by Rajput-JI


Python 3
# Python 3 program of finding
# modulo multiplication
  
# Returns (a * b) % mod
def moduloMultiplication(a, b, mod):
  
    res = 0; # Initialize result
  
    # Update a if it is more than
    # or equal to mod
    a = a % mod;
  
    while (b):
      
        # If b is odd, add a with result
        if (b & 1):
            res = (res + a) % mod;
              
        # Here we assume that doing 2*a
        # doesn't cause overflow
        a = (2 * a) % mod;
  
        b >>= 1; # b = b / 2
      
    return res;
  
# Driver Code
a = 10123465234878998;
b = 65746311545646431;
m = 10005412336548794;
print(moduloMultiplication(a, b, m));
      
# This code is contributed
# by Shivi_Aggarwal


C#
// C# program of finding modulo multiplication
using System;
  
class GFG
{
      
// Returns (a * b) % mod
static long moduloMultiplication(long a,
                            long b,
                            long mod)
{
    long res = 0; // Initialize result
  
    // Update a if it is more than
    // or equal to mod
    a %= mod;
  
    while (b > 0)
    {
        // If b is odd, add a with result
        if ((b & 1) > 0)
            res = (res + a) % mod;
  
        // Here we assume that doing 2*a
        // doesn't cause overflow
        a = (2 * a) % mod;
  
        b >>= 1; // b = b / 2
    }
  
    return res;
}
  
// Driver code
static void Main()
{
    long a = 10123465234878998;
    long b = 65746311545646431;
    long m = 10005412336548794;
    Console.WriteLine(moduloMultiplication(a, b, m));
}
}
  
// This code is contributed 
// by chandan_jnu


PHP
>= 1; // b = b / 2
    }
  
    return $res;
}
  
    // Driver Code
    $a = 10123465234878998;
    $b = 65746311545646431;
    $m = 10005412336548794;
    echo moduloMultiplication($a, $b, $m);
  
// This oce is contributed by ajit
?>


输出:

4652135769797794

时间复杂度: O(log b)
辅助空间: O(1)

注意:只有在标准数据类型中可以表示2 * m时,以上方法才有效,否则会导致溢出。