C ++ - Brent-Pollard rho算法无限循环

时间:2016-05-07 00:25:10

标签: c++ algorithm loops factorization

我有以下功能。我是从两个网站上得到的,并尝试将其改编成我自己的网站,但效果并不好。

当我测试export LC_ALL=en_US.utf-8 export LANG=en_US.utf-8 或者将其作为数字unsigned long int max - 2进行测试时,它将以下代码置于无限循环中,其中4294967293将继续返回相同的值。

我对分解算法非常陌生,并逐步帮助我获得无限循环的原因。

以下代码只是我的“rho”功能。我有另一个名为ys的函数,它与其他每个gdc递归函数相同。

gdc

我调整了以下代码的示例:

修改

我已经完成,因为Amd建议并整理我的代码并将重复的行移动到辅助函数中。但是我仍然在底部附近的unsigned long int rho(unsigned long int n) { if (n == 1) return n; if (n % 2 == 0) return 2; unsigned long int y = rand() % n; unsigned long int x; unsigned long long int ys = y; unsigned long int c; do c = rand() % n; while (c == 0 || c == n - 2); unsigned long int m = 1000; unsigned long int d = 1; unsigned long int q = 1; unsigned long int r = 1; while (d == 1) { x = y; for (int i = 0; i < r; i++) { y = y * y % n; y += c; if (y < c) y += (std::numeric_limits<unsigned long>::max() - n) + 1; y %= n; } int j = 0; while (j < r && d == 1) { ys = y; for (int i = 0; i < m && i < (r-j); i++) { y = y * y % n; y += c; if (y < c) y += (std::numeric_limits<unsigned long>::max() - n) + 1; y %= n; q *= ((x>y) ? x - y : y - x) % n; } d = gcd(q, n); j += m; } r *= 2; } if (d == n) { do { ys = ys * ys % n; std::cout << ys << std::endl; ys += c; if (ys < c) ys += (std::numeric_limits<unsigned long>::max() - n) + 1; ys %= n; d = gcd( ((x>ys) ? x - ys : ys - x) , n); } while (d == 1); } return d; } 部分获得无限循环。出于某种原因,d==n最终基本上返回了之前返回的相同内容,因此它会循环显示一系列值。

f(ys)

2 个答案:

答案 0 :(得分:1)

应始终终止。当你到达算法中的那一点时,x将在周期内(从y开始x并开始使用Brent&#39来检测周期; s循环检测)。价值ysy开始,从x开始,因此它也将在整个周期内继续并最终再次与x见面(参见Floyd或Tortoise和Hare周期)检测)。此时您将拥有gcd(ys,x)==x,最终循环将终止。

发布的实施中有几个错误,我认为可能导致问题:

x = y;
for (int i = 0; i < r; i++)                // should be strictly less than
    ...

    ys = y;
    for (int i = 0; i < min(m, r-j); i++)  // again, strictly less than
    {
        y = f(y, c, n);
        q = (q*abs(x,y)) % n;  // needs "mod" operator AFTER multiplication
    }
    ...

您还可以使用

替换c的初始化
uint64_t c = (rand() % (n-3))+1

如果你想要一个[1,n-3]范围内的数字。

这是Richard P. Brent的原始论文:An Improved Monte-Carlo Factorization Algorithm

答案 1 :(得分:0)

修改
这对我有用,而不是陷入无限循环:

#include<iostream>
#include<stdint.h>

#define min(a,b) (a<b?a:b)
#define abs(x,y) (x > y? x - y : y - x)

uint64_t gcd(uint64_t m, uint64_t n) {
    while (true) {
        int r = m % n;
        if (r == 0) {
            return n;
        }
        m = n;
        n = r;
    }
}
uint64_t f(uint64_t y, uint64_t c, uint64_t n) {
    y = (y * y) % n;
    y += c;
    if (y < c)
        y += (std::numeric_limits<uint32_t>::max() - n) + 1;
    y %= n;
    return y;
}

uint64_t rho(uint64_t n)
{
    if (n == 1) return n;
    if (n % 2 == 0) return 2;

    uint64_t y = rand() % n;
    uint64_t x;
    uint64_t ys = y;
    uint64_t c;
    do c = rand() % n; while (c == 0 || c == n - 2);
    uint64_t m = 1000;
    uint64_t d = 1;
    uint64_t q = 1;
    uint64_t r = 1;
    do
    {
        x = y;
        for (int i = 0; i <= r; i++)
            y = f(y, c, n);

        int j = 0;
        do
        {
            ys = y;
            for (int i = 0; i <= min(m, r - j); i++)
            {
                y = f(y, c, n);
                q *= (abs(x, y) % n);
            }
            d = gcd(q, n);
            j += m;
        } while (j < r && d == 1);
        r *= 2;
    } while (d == 1);
    if (d == n)
    {
        do
        {
            ys = f(ys, c, n);
            d = gcd(abs(x, ys), n);
        } while (d == 1);
    }
    return d;
}
int main() {
    std::cout << rho(std::numeric_limits<uint32_t>::max() - 2) << "\n";     //9241
}

<强>旧
根据改进的蒙特卡罗分解算法:http://wwwmaths.anu.edu.au/~brent/pd/rpb051i.pdf
PP:182-183
错误:ys = x * x%n;
正确:ys = ys * ys%n; // ys = f(ys)

请使用来自stdint.h的uint32_t或uint64_t ...以获得良好和干净的编码风格:

#include<iostream>
#include<stdint.h>

int gcd(int m, int n) {
    while (true) {
        int r = m % n;
        if (r == 0) {
            return n;
        }
        m = n;
        n = r;
    }
}

#define min(a,b) (a<b?a:b)
#define abs(x,y) (x > y? x - y : y - x) 

uint32_t f(uint32_t y, uint32_t c, uint32_t n) {
    y = (y * y) % n;
    y += c;
    if (y < c)
        y += (std::numeric_limits<uint32_t>::max() - n) + 1;
    y %= n;
    return y;
}

//http://wwwmaths.anu.edu.au/~brent/pd/rpb051i.pdf
//pp:182-183
uint32_t rho(uint32_t n) {
    if (n == 1) return n;
    if (n % 2 == 0) return 2;

    uint32_t y = rand() % n; // y = x0
    uint32_t x;
    uint64_t ys = y;
    uint32_t c;
    do { c = rand() % n; } while (c == 0 || c == n - 2);
    uint32_t m = 1000;
    uint32_t d = 1;
    uint32_t q = 1;
    uint32_t r = 1;
    do
    {
        x = y;
        for (int i = 1; i <= r; i++)  y = f(y, c, n);
        int j = 0;
        do
        {
            ys = y;
            for (int i = 1; i <= min(m, r - j); i++)
            {
                y = f(y, c, n);
                q = q * abs(x, y) % n;
            }
            d = gcd(q, n);
            j += m;
        } while (j < r && d == 1);
        r *= 2;
    } while (d == 1);
    if (d == n)
    {
        do
        {
            ys = f(ys, c, n);//not:     ys = f(x,c,n);      
            d = gcd(abs(x, ys), n);
        } while (d == 1);
    }
    return d;
}