最近,我从此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;
}
这是该页面上给定实现的错误吗?该算法能否找不到某些数字的因数?
答案 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