【问题标题】:Optimising code for modular arithmetic优化模运算的代码
【发布时间】:2013-01-22 02:10:29
【问题描述】:

我正在尝试计算下面的大数表达式。

由于这个表达式的值会很大,我只需要这个表达式的值取模一些素数。假设这个表达式的值为x,我选择素数1000000007;我在找x % 1000000007

这是我的代码。

#include<iostream>
#define MOD 1000000007
using namespace std;
int main()
{
    unsigned long long A[1001];
    A[2]=2;
    for(int i=4;i<=1000;i+=2)
    {
        A[i]=((4*A[i-2])/i)%MOD;
        A[i]=(A[i]*(i-1))%MOD;

    while(1)
    {
        int N;
        cin>>N;
        cout<<A[N];
    }
}

但是对于较大的 N 值,即使如此多的优化也会失败。例如,如果 N 为 50,则正确的输出是 605552882,但这给了我 132924730。如何进一步优化以获得正确的输出?

注意:我只是将 N 视为偶数。

【问题讨论】:

标签: c++ math optimization modular-arithmetic


【解决方案1】:

在进行模运算时,没有除法之类的操作。取而代之的是,您取分母的模逆并相乘。模逆是使用 Etienne Bezout 在 1779 年发现的扩展欧几里得算法计算的:

# return y such that x * y == 1 (mod m)
function inverse(x, m)
    a, b, u := 0, m, 1
    while x > 0
        q, r := divide(b, x)
        x, a, b, u := b % x, u, x, a - q * u
    if b == 1 return a % m
    error "must be coprime"

divide 函数返回商和余数。上面给出的所有赋值运算符都是同时赋值,首先计算所有右侧,然后同时分配所有左侧。您可以在my blog 了解更多关于模运算的信息。

【讨论】:

    【解决方案2】:
    1. 对于初学者来说根本不需要模除,你的公式可以重写如下:

      N!/((N/2)!^2) =(1.2.3...N)/((1.2.3...N/2)*(1.2.3...N/2)) =((N/2+1)...N)/(1.2.3...N/2))

      • 好的,现在您将较大的数字除以较小的数字
      • 因此您可以通过将除数和除数相乘来迭代结果
      • 所以展位子结果的大小相似
      • 任何时候两个数字都可以整除 2 将它们左移
      • 这将确保不会溢出
      • 如果您处于 (N/2) 的和位置!而不是只为其余部分继续乘法。
      • 任何时候两个子结果都可以被任何东西整除
      • 直到你被除以 1
      • 在此之后,您可以使用模运算进行乘法运算,直到正常结束。
    2. 有关更高级的方法,请参阅此。

      • 不!和(N/2)!比第一眼看起来更容易分解
      • 我已经解决了一段时间了,...
      • 这是我发现的:Fast exact bigint factorial
      • 简而言之,N!并且 ((N/2)!)^2 将完全消失。
      • 只有简单的素数分解 + 4N 1N 修正会提醒

    解决方案:

    I. (4N!)=((2N!)^2) . mul(i=all primes<=4N) of [i^sum(j=1,2,3,4,5,...4N>=i^j) of [(4N/(i^j))%2]]
    II. (4N)!/((4N/2)!^2) = (4N)!/((2N)!^2)
    ----------------------------------------
    I.=II. (4N)!/((2N)!^2)=mul(i=all primes<=4N) of [i^sum(j=1,2,3,4,5,...4N>=i^j) of [(4N/(i^j))%2]]
    
    • 唯一的问题是 N 必须能被 4 整除...因此在所有方面都是 4N。
    • 如果您有 N%4!=0,则求解 N-N%4 并且结果由 misin 1-3 数字正确。

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 2013-01-30
      • 1970-01-01
      • 1970-01-01
      • 2012-12-12
      • 2014-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多