한 양의 정수
밀러-라빈 소수 판정법은 비결정적으로 소수를 판정하는 알고리즘이다. 그러나 long long
범위 내에서는 결정적으로 판정할 수 있어, 비로소 PS에 사용할 수 있게 된다. 우선 페르마 소수 판별법에 대해 알아보자.
TOC
페르마 소수 판별법
페르마의 소정리를 이용하여 소수를 판별하는 것이다. 페르마의 소정리에 대해 알아보자.
페르마의 소정리에 대한 증명은 여럿 있지만, 그 중 완전한 잉여류 집합을 활용한 증명을 소개하겠다.
각 원소를 모듈로
이제
왼쪽에서
이다. 양변에서
따라서, 페르마의 소정리가 성립한다.
밀러-라빈 소수 판별법
밀러-라빈 소수 판별법은 페르마 판별법을 확장한 것이다.
홀수
이는 페르마의 소정리의 합동식을 인수분해할 수 있도록 한다.
이나
가 성립하는 지를 확인한다.
어떤 밑
페르마 판별법와 유사하게, 합성수에 대해 위의 식들이 모두 만족할 가능성도 있다. 이 경우 해당 밑
다음은 64비트 정수에 대해 밀러-라빈 소수 판별법을 구현한 것이다.
using u64 = uint64_t;
using u128 = __uint128_t;
u64 binpower(u64 base, u64 e, u64 mod) {
u64 result = 1;
base %= mod;
while (e) {
if (e & 1)
result = (u128)result * base % mod;
base = (u128)base * base % mod;
e >>= 1;
}
return result;
}
bool check_composite(u64 n, u64 a, u64 d, int s) {
u64 x = binpower(a, d, n);
if (x == 1 || x == n - 1)
return false;
for (int r = 1; r < s; r++) {
x = (u128)x * x % n;
if (x == n - 1)
return false;
}
return true;
};
bool MillerRabin(u64 n, int iter=5) { // n이 아마도 소수이면 true, 아니면 false를 반환.
if (n < 4)
return n == 2 || n == 3;
int s = 0;
u64 d = n - 1;
while ((d & 1) == 0) {
d >>= 1;
s++;
}
for (int i = 0; i < iter; i++) {
int a = 2 + rand() % (n - 3);
if (check_composite(n, a, d, s))
return false;
}
return true;
}
밀러-라빈 테스트를 수행하기 전에, 먼저 몇 개의 소수들이 약수인지 추가로 검사할 수 있다.
대부분의 합성수는 매우 작은 소인수를 가지므로, 이를 통해 테스트 속도를 크게 향상시킬 수 있다.
예를 들어, 전체 수의
결정론적인 버전
밀러는
결과적으로 32비트 정수를 판별할 때는 첫 4개의 소수 밑, 즉 2, 3, 5, 7만 검사하면 충분하다. 이 테스트를 통과하지 못하는 가장 작은 합성수는
이다.
또한 64비트 정수를 판별할 때는 첫 12개의 소수 밑수, 즉 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37만 검사하면 충분하다.
다음은 결정론적 밀러-라빈 소수 판별법의 구현이다.
bool MillerRabin(u64 n) { // n이 소수이면 true, 아니면 false를 반환.
if (n < 2)
return false;
int r = 0;
u64 d = n - 1;
while ((d & 1) == 0) {
d >>= 1;
r++;
}
for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
if (n == a)
return true;
if (check_composite(n, a, d, r))
return false;
}
return true;
}
또한 7개의 밑수, 즉 2, 325, 9375, 28178, 450775, 9780504, 1795265022만으로 검사를 수행할 수도 있다. 하지만 이 숫자들(2를 제외하고)은 소수가 아니므로, 검사하는 수가 이들 밑수의 소인수인 2, 3, 5, 13, 19, 73, 193, 407521, 299210837 중 하나와 같은지도 추가로 확인해야 한다.
참고 문헌
- jakobkogler, et al. Primality tests. cp-algorithms.com.