Lucas 疑似素数検定を使用して、数値nが素数か合成数かを判断する関数を作成しようとしています。現時点では、標準テストで作業していますが、それが機能するようになったら、強力なテストを作成します。私はBaillie と Wagstaff による論文を読んでおり、 trn.cファイルで Thomas Nicely による実装に従っています。
完全なテストにはいくつかのステップが含まれることを理解しています: 小さな素数による割り算の試行、nが平方でないことの確認、基数 2 に対する強力な疑似素数テストの実行、そして最後にルーカスの疑似素数テスト。他のすべての部分は処理できますが、Lucas 疑似素数検定に問題があります。Pythonでの私の実装は次のとおりです。
def gcd(a, b):
while b != 0:
a, b = b, a % b
return a
def jacobi(a, m):
a = a % m; t = 1
while a != 0:
while a % 2 == 0:
a = a / 2
if m % 8 == 3 or m % 8 == 5:
t = -1 * t
a, m = m, a # swap a and m
if a % 4 == 3 and m % 4 == 3:
t = -1 * t
a = a % m
if m == 1:
return t
return 0
def isLucasPrime(n):
dAbs, sign, d = 5, 1, 5
while 1:
if 1 < gcd(d, n) > n:
return False
if jacobi(d, n) == -1:
break
dAbs, sign = dAbs + 2, sign * -1
d = dAbs * sign
p, q = 1, (1 - d) / 4
print "p, q, d =", p, q, d
u, v, u2, v2, q, q2 = 0, 2, 1, p, q, 2 * q
bits = []
t = (n + 1) / 2
while t > 0:
bits.append(t % 2)
t = t // 2
h = -1
while -1 * len(bits) <= h:
print "u, u2, v, v2, q, q2, bits, bits[h] = ",\
u, u2, v, v2, q, q2, bits, bits[h]
u2 = (u2 * v2) % n
v2 = (v2 * v2 - q2) % n
if bits[h] == 1:
u = u2 * v + u * v2
u = u if u % 2 == 0 else u + n
u = (u / 2) % n
v = (v2 * v) + (u2 * u * d)
v = v if v % 2 == 0 else v + n
v = (v / 2) % n
if -1 * len(bits) < h:
q = (q * q) % n
q2 = q + q
h = h - 1
return u == 0
これを実行すると、83 や 89 などの素数isLucasPrime
が返されますが、これは正しくありません。False
また、コンポジット 111 に対しても返されますFalse
が、これは正しいです。そして、複合 323 を返します。これは、を返す必要False
があるルーカス疑似素数であることがわかっています。実際、私がテストしたすべてのnを返します。isLucasPrime
True
isLucasPseudoprime
False
いくつか質問があります:
1) 私は C/GMP の専門家ではありませんが(n+1)/2
、他の著者がビットを左から右に実行するのに対し、Nicely は右から左 (最下位から最上位) のビットを実行しているように思えます。上記のコードは左から右にビットを実行しますが、右から左にビットを実行しようとしても同じ結果になりました。正しい順番は?
2) Nicelyが 1 ビットのu変数とv変数のみを更新するのは奇妙に思えます。これは正しいです?チェーンのインデックスは各ステップで増加するため、ループのたびに 4 つのルーカス チェーン変数すべてを更新することを期待していました。
3) 私は何を間違えましたか?