假设我为x选择一个介于0
和2147483647
之间的值。 (Int32.MaxValue)
我试图弄清楚如何找到a,b,n
的值,以便(a^b)%n=x
我已经知道我可以使用ModPow来验证值,但是我不知道如何找到合适的a,b和n。
#include <iostream>
/// Calculate (a^b)%n
/// \param a The base
/// \param b The exponent
/// \param n The modulo
/// \return (a^b)%n
int ModPow(int a, int b, int n) {
long long x = 1, y = a;
while (b > 0) {
if (b % 2 == 1) {
x = (x * y) % n; // multiplying with base
}
y = (y * y) % n; // squaring the base
b /= 2;
}
return x % n;
}
int main() {
int x = 1337;
// How to find a,b,n so that (a^b)%n=x
int a = ?;
int b = ?;
int n = ?;
if(x == ModPow(a,b,n))
printf("ok");
return 0;
}
答案 0 :(得分:2)
int n = 2147483647
int a = ModPow(x, 9241, n);
int b = 464773;
n = 2 31 − 1是质数。因此,由于Fermat's little theorem, x n mod n = x 和 x n − 1 mod n = 1(除非 x = 0)所以 x 2 n − 1 mod n = x 。 2 n − 1 = 9241×464773。因此(( x 9241 mod n ) 464773 mod n = x 。请注意,您需要 x < n 才能起作用。如果 n 也是31位(即带符号)整数,则 x = 2147483647也将不起作用。
我花了一段时间才来到这里;很长一段时间以来,我在得到这个简单的解决方案之前就已经将这个答案弄混了Carmichael numbers和Carmichael function。有关详细信息,请参见edit history。
答案 1 :(得分:1)
产生以下表达式给出的余数,其中 e1 是第一个操作数,而 e2 是第二个操作数: e1 –(e1 / e2)* e2
因此,无论x
的最大值是多少,n
都必须更大。由于您要使用n
作为int
进行验证,并且要指定范围:0
和numeric_limits<int>::max()
,必须必须是唯一范围,并使n
成为int
的唯一可能值是:numeric_limits<int>::max()
。
使用n
强制我们的方程有效地变为: a
b
= x
。
在这里,我们需要检查x
不是1
,如果它是 b
= 0 并且a
可以是我们法律范围内的任何东西,因此我们可以任意选择 a
= 2 。但是要禁止这个:
我们的要求是:
a
<x
,而a
是int
b
<x
,而b
是int
给定x
,我们可以搜索a
和b
的组合,如下所示:
auto a = 0.0;
auto b = 1;
if(x == 1) {
a = 2.0;
b = 0;
} else {
while((a = pow(x, 1.0 / ++b)) > 2.0) {
double dummy;
if(modf(a, &dummy) == 0.0) {
break;
}
}
}
在这一点上,如果 a
> = 2.0 ,那么可以找到有效的解决方案。如您所知,pow
是一个非常昂贵的函数,因此对于较大值的x
可能需要很长时间才能执行,我个人建议您找到一个{{ 1}}和a
,针对存在该对的每个数字,并将它们存储在b
中,并对其进行查询。
无论如何,这是工作代码的演示: