模数

时间:2015-04-27 23:10:37

标签: c++ modulo largenumber

我编写了一个计算一系列数字的算法,但它们最终会被大量存储在unsigned long long中。这就是我每次计算下一个数字时决定采用模数的原因。这是我的功能:

#define MOD 1000000007

template <typename T>
T modpow(T base, T exp, T modulus) {
    base %= modulus;
    T result = 1;
    while (exp > 0) {
        if (exp & 1) result = (result * base) % modulus;
        base = (base * base) % modulus;
        exp >>= 1;
    }
    return result;
}

vector<unsigned long long> B(int n) {
    vector<unsigned long long> points;
    vector<unsigned long long> cum_points;

    points.push_back(0);
    points.push_back(0);

    cum_points = points;

    unsigned long long prev = 0;
    if (n >= 2){
        for (int i = 0; i <= n - 2; i++) {
            prev += cum_points[i];
            prev %= MOD;
            points.push_back((modpow((unsigned long long)2, (unsigned long long)i, (unsigned long long) MOD)+prev)%MOD);
            cum_points.push_back((cum_points[i+1]+points[i+2])%MOD);
        }
    }
    return points;
}

返回带有一系列数字的向量:

0, 0, 1, 2, 5, 12, 28, 64, 144, 320, 704, 1536年, 3328, ...

等等......

问题是当n > 50模数稍微偏离时: (第一个值是在代码中没有模数的情况下计算的值,等号后面的值是代码中模数的结果。)

50: 1759218604441600 % 1000000007 = 592127074; this is the right answer
51: 3588805953060860 % 1000000007 = 927939229; this should be: 927939225

每次n越高,错误就越大。这个小偏差来自哪里?

一些可能的问题:

  • modpow()以某种方式在数字时没有给出正确的答案 超过一定的长度。 这不是问题
  • 数学有一些错误,但我相信我用正确的方法使用了以下等式:

(a*b) mod c = ((a mod c)*(b mod c)) mod c

(a + b) mod c = ((a mod c)+(b mod c)) mod c

  • 我的代码中也可能有一个错误的变量类型,虽然我不知道在哪里。

编辑:我排除了一些可能出现的问题,问题似乎在于previ == 48的计算中。

1 个答案:

答案 0 :(得分:-1)

您可以检查模数是否足够小。您是否检查过系统中未签名的long long的大小?

std::cout << std::numeric_limits<unsigned long long>::max();

检查时,您还可以检查unsigned int的大小 同时。我不确定它们是否必然不同。

您的模数有10位数,因此两个数字的乘积最多可以有20位数。如果你的最大无符号长long小于MOD * MOD,那么你可能会遇到溢出错误。

公式中的错误可能会在n = 51之前出现。

评论: 如果您使用的是C ++ 11标准,为什么不用

替换该宏
constexpr unsigned long long MOD = 1000000007;

此外,在您调用modpow的地方,您可以通过简单地调用所需的特定函数来避免所有这些强制转换为unsigned long longmodpow<unsigned long long>。然后参数将自动转换为正确的类型。