Shanks的平方形式分解实现

时间:2018-10-10 18:41:56

标签: c factors factorization

最近,我从此wiki page开始研究Shanks的平方形式分解 该页面上提供了C的实现。我在测试该功能时,发现该功能找不到27的因数。

这是给定的C函数:

#include <inttypes.h>
#define nelems(x) (sizeof(x) / sizeof((x)[0]))

const int multiplier[] = {1, 3, 5, 7, 11, 3*5, 3*7, 3*11, 5*7, 5*11, 7*11, 3*5*7, 3*5*11, 3*7*11, 5*7*11, 3*5*7*11};

uint64_t SQUFOF( uint64_t N )
{
    uint64_t D, Po, P, Pprev, Q, Qprev, q, b, r, s;
    uint32_t L, B, i;
    s = (uint64_t)(sqrtl(N)+0.5);
    if (s*s == N) return s;
    for (int k = 0; k < nelems(multiplier) && N <= UINT64_MAX/multiplier[k]; k++) {
        D = multiplier[k]*N;
        Po = Pprev = P = sqrtl(D);
        Qprev = 1;
        Q = D - Po*Po;
        L = 2 * sqrtl( 2*s );
        B = 3 * L;
        for (i = 2 ; i < B ; i++) {
            b = (uint64_t)((Po + P)/Q);
            P = b*Q - P;
            q = Q;
            Q = Qprev + b*(Pprev - P);
            r = (uint64_t)(sqrtl(Q)+0.5);
            if (!(i & 1) && r*r == Q) break;
            Qprev = q;
            Pprev = P;
        };
        if (i >= B) continue;
        b = (uint64_t)((Po - P)/r);
        Pprev = P = b*r + P;
        Qprev = r;
        Q = (D - Pprev*Pprev)/Qprev;
        i = 0;
        do {
            b = (uint64_t)((Po + P)/Q);
            Pprev = P;
            P = b*Q - P;
            q = Q;
            Q = Qprev + b*(Pprev - P);
            Qprev = q;
            i++;
        } while (P != Pprev);
        r = gcd(N, Qprev);
        if (r != 1 && r != N) return r;
    }
    return 0;
}

这是该页面上给定实现的错误吗?该算法能否找不到某些数字的因数?

1 个答案:

答案 0 :(得分:0)

Wikipedia页面中的算法不检查任何整数除法的分母是否等于零。

我为N的前32768个值测试了slightly modified version of it(我也使用了C ++,这可能是OP实际使用的,因为他们在注释中提到了“ C ++ STL的gcd函数”的用法) ,获得:

N:      3  Q == 0 in the first division
N:      5  Q == 0 in the first division
N:      7  Q == 0 in the first division
N:     11  Q == 0 in the first division
N:     27  Q == 0 in the first division
N:    363  Q == 0 in the first division
N:    867  Q == 0 in the first division
N:   1445  Q == 0 in the first division
N:   5043  Q == 0 in the first division
N:   6845  Q == 0 in the first division
N:   7803  Q == 0 in the first division
N:  10443  Q == 0 in the first division
N:  11163  Q == 0 in the first division
N:  13467  Q == 0 in the first division
N:  14283  Q == 0 in the first division
N:  18491  Q == 0 in the first division
N:  18723  Q == 0 in the first division
N:  23763  Q == 0 in the first division
N:  30603  Q == 0 in the first division
N:  31827  Q == 0 in the first division

您会注意到,第一种情况是质数,并且也出现在multipliers数组中。

在执行第一次除法的内部循环之前,变量Q的计算方式基本上为

D = multiplier[k]*N;
Po = sqrtl(D);
Q = D - Po*Po;

因此,当Q是一个完美正方形时,D为零。您可以添加几行code来处理这些极端情况:

const uint64_t multiplier[] = {
    1, 3, 5, 7, 11, 3*5, 3*7, 3*11, 5*7, 5*11, 7*11, 3*5*7,
    3*5*11, 3*7*11, 5*7*11, 3*5*7*11
};
const uint64_t results[] = {
    1, 0, 0, 0, 0, 3, 3, 3, 5, 5, 7, 3, 3, 3, 5, 3
};
    // ... inside the k loop
    if ( multiplier[k] == N )   
        return results[k];
    // ... calculate Q as before
    if (Q == 0) 
        return std::gcd(multiplier[k], N);
    // ... rest of the loop