C++ c+中俄罗斯农民算法的整数溢出+;
我遇到了一个俄罗斯农民指数法(RPE)的问题,该方法计算指数的速度比传统方法计算x的n次方快得多。C++ c+中俄罗斯农民算法的整数溢出+;,c++,algorithm,integer-overflow,C++,Algorithm,Integer Overflow,我遇到了一个俄罗斯农民指数法(RPE)的问题,该方法计算指数的速度比传统方法计算x的n次方快得多。 常规方法 int power(int base, int exponent) { int result = 1; for(register int i = 1; i <= exponent; i++) { result *= base; } return result; } 问题说明输入由定义查询数量的整数q组成。每个查询由4个数字组成,用空
常规方法
int power(int base, int exponent) {
int result = 1;
for(register int i = 1; i <= exponent; i++) {
result *= base;
}
return result;
}
问题说明输入由定义查询数量的整数q
组成。每个查询由4个数字组成,用空格a、b、k、m
分隔。对于每个查询,我必须找到z=(a+ib)^k
,因为re(z)
和im(z)
的值可能非常大,所以我必须打印re(z)mod m
和im(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
由于上述表达式的结果可能是负值,因此需要替换
((ar*br)%m-(ai*bi)%m)%m
与
((ar*br)%m+m-(ai*bi)%m)%m
因为你可以从上面的表达式中得到一个负值,这是一个非常简洁的算法,我最后写了自己的算法 我不认为在计算过程中减少中间结果会如何使数学工作,恰恰相反 不过,使用复杂的方法是可行的 我计划将此算法添加到我的工具箱中,因此它与您的实现略有不同。我使用了论文的算法,它减少了1次乘法运算。处理负数模的方法在main()中
#包括
#包括
模板
T fastExp(tx,无符号整数e)
{
如果(e==0)
返回T(1);
而(!(e&1))
{
x*=x;
e>>=1;
}
自动y=x;
e>>=1;
while(e)
{
x*=x;
国际单项体育联合会(e&1)
y*=x;
e>>=1;
}
返回y;
}
int main()
{
std::配合物x{8,2};
自动y=fastExp(x,10);
长k=1000000000LL;
std::复z;
y-={floor(y.real()/k),floor(y.imag()/k)};
复数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这是一个如此简洁的算法,我最终编写了自己的算法
我不认为在计算过程中减少中间结果会如何使数学工作,恰恰相反
不过,使用复杂的方法是可行的
我计划将此算法添加到我的工具箱中,因此它与您的实现有点不同。我使用了论文中的算法,它可以减少1次乘法。处理负数模的方法在main()中
#包括
#包括
模板
T fastExp(tx,无符号整数e)
{
如果(e==0)
返回T(1);
而(!(e&1))
{
x*=x;
e>>=1;
}
自动y=x;
e>>=1;
while(e)
{
x*=x;
国际单项体育联合会(e&1)
y*=x;
e>>=1;
}
返回y;
}
int main()
{
std::配合物x{8,2};
自动y=fastExp(x,10);
长k=1000000000LL;
std::复z;
y-={floor(y.real()/k),floor(y.imag()/k)};
复数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什么是奇怪的答案?展示一些预期输出/要添加到gdelab建议中的输出的示例。如果您为此编写一个测试工具,它可能会很好地为您服务。请花一些时间阅读。为了帮助您进行调试,请尝试将大表达式分解为小表达式,以便更容易地查看intermediate results.你对代码进行了过度设计。这不应该是一个类。读取输入是一个与求幂运算完全无关的问题。你使用复数的理由我也不清楚:它们不会让溢出神奇地消失。使用调试器!奇怪的答案是什么?显示一些示例预期输出/您要添加到gdelab建议的内容中的输出如果您为此编写一个测试工具,可能会对您很有帮助。请花一些时间阅读。为了帮助您进行调试,请尝试将大型表达式分解为小型表达式,以便更容易看到中间结果。您对代码的设计过于复杂。这说明uld不是一个类。读取输入是一个与求幂完全无关的问题。我也不清楚你使用复数的理由:它们不会神奇地消除溢出。使用调试器!@MichaëlRoy,但为什么?表达式if(ar*br)的末尾有%m
%m>=0
然后((ar*br)%m+m>=m
这是不对的。无论如何,在计算x**y时使用中间值的任意模在数学上是不合理的。@MichaëlRoy,这没关系,因为在最后我们得到了除以m
@MichaëlRoy的余数,但是为什么呢?表达式if的末尾有%m
(ar*br)%m>=0
然后((ar*br)%m+m>=m
这是不对的。无论如何,在计算x**y时使用中间值的任意模在数学上是不合理的。@MichaëlRoy,这没关系,因为最后我们得到了被m
除的余数。
#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;
}
#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";
}