找出a,b,n,以便(a ^ b)%n = x

时间:2018-06-22 18:07:21

标签: c++ math modular-arithmetic

假设我为x选择一个介于02147483647之间的值。 (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;
}

2 个答案:

答案 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 numbersCarmichael function。有关详细信息,请参见edit history

答案 1 :(得分:1)

modulus operator

  

产生以下表达式给出的余数,其中 e1 是第一个操作数,而 e2 是第二个操作数: e1 –(e1 / e2)* e2

因此,无论x的最大值是多少,n都必须更大。由于您要使用n作为int进行验证,并且要指定范围:0numeric_limits<int>::max()必须必须是唯一范围,并使n成为int的唯一可能值是:numeric_limits<int>::max()

使用n强制我们的方程有效地变为: a b = x
在这里,我们需要检查x不是1,如果它是 b = 0 并且a可以是我们法律范围内的任何东西,因此我们可以任意选择 a = 2 。但是要禁止这个:

我们的要求是:

  • 1 <a <x ,而aint
  • 1 <b <x ,而bint

给定x,我们可以搜索ab的组合,如下所示:

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中,并对其进行查询。
无论如何,这是工作代码的演示:

Live Example