C 中俄罗斯农民算法中的整数溢出

Integer overflow in Russian Peasant Algorithm in c++

本文关键字:整数 溢出 农民 俄罗斯 算法      更新时间:2023-10-16

i遇到了俄罗斯农民漏洞(RPE(链接的问题,它的评估速度要比传统的发现X的传统方法快得多,该方法添加了n。



br/>常规方法

int power(int base, int exponent) {
    int result = 1;
    for(register int i = 1; i <= exponent; i++) {
        result *= base;
    }
    return result;
}

我实现了复数的算法,鉴于乘法可以导致溢出,我将re(z) mod mim(z) mod m打印为2个空间分离的整数,但是我的实现不正确,因为它引起了一些怪异的答案,任何人都可以指出。问题以及如何纠正它。这是我的代码

#include<iostream>
#include<complex>
using namespace std;
class Solution {
    int m;
    long long int k;
    complex<long long int> num;
    complex<long long int> russianPeasantExponentiation(), multiply(complex<long long int>, complex<long long int>);
public:
    void takeInput(), solve();
};
void Solution::takeInput() {
    int a, b;
    cin >> a >> b >> k >> m;
    num = complex<long long int> (a, b);
}
void Solution::solve() {
    complex<long long int> res = russianPeasantExponentiation();
    cout << real(res) << " " << imag(res) << endl;
}
complex<long long int> Solution::russianPeasantExponentiation() {
    complex<long long int> temp1(1, 0), temp2 = num;
    while(k) {
        if(k % 2) {
            temp1 = multiply(temp1, temp2);
        }
        temp2 = multiply(temp2, temp2);
        k /= 2;
    }
    return temp1;
}
complex<long long int> Solution::multiply(complex<long long int> a, complex<long long int> b) {
    long long int ar = real(a), ai = imag(a), br = real(b), bi = imag(b);
    complex<long long int> result(((ar * br) % m - (ai * bi) % m) % m, ((ar * bi)%m + (ai * br)%m)%m);
    return result;
}
int main() {
    int q;
    cin >> q;
    while(q--) {
        Solution obj;
        obj.takeInput();
        obj.solve();
    }
    return 0;
}

这些问题指出输入由一个整数q组成,该整数定义了NO。查询。每个查询由4个数字组成,该数字由空间a, b, k, m隔开。对于每个查询,我必须找到z = (a + ib)^k,因为re(z)im(z)的值可能很大,因此我必须打印re(z) mod mim(z) mod m

问题在测试案例中发生 8 2 10 1000000000预期的是 880332800 927506432,我的排名是 -119667200 -72493568

您需要替换

((ar * br) % m - (ai * bi) % m) % m

((ar * br) % m + m - (ai * bi) % m) % m

因为您可以由于上述表达而获得负值

这真是一个整洁的算法,我最终写了自己的!

我看不出计算过程中的中间结果如何使数学起作用,这恰恰相反。

使用复杂&lt; double&gt;不过。

我计划将此算法添加到我的工具箱中,因此与您的实现有所不同。我使用了纸张的算法,该算法少1个乘法。处理负数模量的方法在main((

#include <complex>
#include <iostream>
template <typename T>
T fastExp(T x, unsigned int e)
{
    if (e == 0)
        return T(1);
    while (!(e & 1))
    {
        x *= x;
        e >>= 1;
    }
    auto y = x;
    e >>= 1;
    while (e)
    {
        x *= x;
        if (e & 1)
            y *= x;
        e >>= 1;
    }
    return y;
}

int main()
{
    std::complex<double> x{ 8, 2 };
    auto y = fastExp(x, 10);
    long long k = 1000000000LL;
    std::complex<double> z;
    y -= { floor(y.real() / k), floor(y.imag() / k) };
    std::complex<long long> r{ (long long)y.real(), (long long)y.imag() };
    while (r.real() < 0)
        r._Val[0] += k;
    while (r.imag() < 0)
        r._Val[1] += k;
    std::cout << "result: " << r.real() << " + " << r.imag() << " i" << "n";
}