繁体   English   中英

如何在不到1秒的时间内计算2 ^ x mod n = 1

[英]How to Calculate 2^x mod n = 1 in less than 1 second

我想编写计算2^x mod n = 1我们有n是一个integer但是,我们应该计算x 。我写了代码但是我的代码在大n中工作太慢了。你能建议我一个好方法工作不到1秒就可以解决这个问题。
这是我的代码:

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
    long long int n,cntr=1,cheak;
    cin >> n;
    while (1)
    {
        if (n % 2 == 0)
        {
            break;
        }
        cheak=pow(2, cntr);
        if (cheak % n == 1)
            break;
        cntr++;
    }
    cout << cntr << endl;
} 

有些建议修改您当前的方法: 注意 :接下来是更好的方法!

  • long long int更改为unsigned long long int 这会再给你一点。
  • while (1)更改为while (cntr < 64) unsigned long long的大小可能只有64位。 (它保证至少为64位,但不大于此。)然后,您需要检查循环是否成功。
  • 改变cheak计算2 n1ull << cntr 确保包含ull后缀,表示这是一个unsigned long long

<<运算符向左移位。 将所有位向左移位1会使数字的整数值加倍,假设没有位从值的左侧“移开”。 所以, 1 << n将计算2 n

后缀ull表示整数常量是unsigned long long 如果省略此后缀,则1将被视为整数,而高于31的移位值将无法执行您想要的操作。


但是 ,以上所有内容仅仅是对您当前方法的改进 值得理解这些改进以更好地理解语言。 但是,他们并没有看到更大的图景。

模块化乘法允许你找到(A * B)mod C为((A mod C)*(B mod C))mod C.这对我们有什么帮助?

我们可以用一种只将NX限制为机器整数精度的方式重写整个算法,而不是2 N

int main()
{
    unsigned int modulus;
    unsigned int raised = 2;
    int power = 1;

    std::cin >> modulus;

    if (modulus % 2 == 1)
    {
        while (raised % modulus != 1)
        {
            raised = ((unsigned long long)raised * 2) % modulus;
            power++;
        }

        std::cout << power << std::endl;
    } else
    {
        std::cout << "modulus must be odd" << std::endl;
    }
}

unsigned long long允许modulus大到2 32 - 1,假设unsigned int是32位,没有计算溢出。

通过这种方法,即使对于非常大的输入,我也能够非常快速地找到答案。 例如, 111111111返回667332 我使用任意精度计算器bc验证了2 677332 mod 111111111 == 1。

它非常快。 它在我的电脑上在不到0.07秒的时间内计算出2 2323860 mod 4294967293 == 1。


Epilog :这突出了编程中的一个重要原则:实际上,这是一个数学问题而不是编程问题。 找到一个有效的解决方案需要了解有关问题域的更多信息,而不是了解C ++。 一旦我们确定了正确的数学方法,实际的C ++代码就是微不足道的。

它通常是这样的,无论是数学还是其他算法方面。 并且,你应该不会惊讶地发现离散数学就是我们的许多图形和集合算法的来源。 编程语言本身就是大局的一小部分。

对于1和ceil(sqrt(n))之间的每个k ceil(sqrt(n)) ,计算2^k mod n2^(k ceil(sqrt(n))) mod n 然后计算每个2^k的模逆。 将所有inverse(2^k) s分类为数组foo ,将2^(k ceil(sqrt(n)) s分类为数组bar 。两个数组之间至少有一个共同的值;找到它比较说inverse(2^a) = 2^(b ceil(sqrt(n))) 。然后2^(a + b ceil(sqrt(n))) = 1 (mod n)

你教授的幽默感怎么样?

#include <iostream>
int main() { std::cout << 0 << '\n'; }

总是按照规定打印出问题的正确答案。

pow在计算中相当昂贵,但是如果你有2作为它的第一个参数,你可以更好地向左移动,因为左移等于2乘以:

cheak = (1 << cntr);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM