1 module dkh.numeric.prime;
2 
3 import std.traits;
4 import dkh.int128;
5 
6 ///
7 ulong ulongPowMod(U)(ulong x, U n, ulong md)
8 if (isIntegral!U || is(U == BigInt)) {
9     x %= md;
10     ulong r = 1;
11     while (n) {
12         if (n & 1) {
13             r = mul128(r, x).mod128(md);
14         }
15         x = mul128(x, x).mod128(md);
16         n >>= 1;
17     }
18     return r % md;
19 }
20 
21 /// xの約数一覧を返す
22 T[] divisorList(T)(T x) {
23     import std.algorithm : sort;
24     T[] res;
25     for (T i = 1; i*i <= x; i++) {
26         if (x%i == 0) {
27             res ~= i;
28             if (i*i != x) res ~= x/i;
29         }
30     }
31     sort(res);
32     return res;
33 }
34 
35 ///
36 unittest {
37     import std.range, std.algorithm;
38     assert(equal(divisorList(1), [1]));
39     assert(equal(divisorList(2), [1, 2]));
40     assert(equal(divisorList(4), [1, 2, 4]));
41     assert(equal(divisorList(24), [1, 2, 3, 4, 6, 8, 12, 24]));
42 }
43 
44 /// xの素因数一覧を返す
45 T[] factorList(T)(T x) {
46     T[] res;
47     for (T i = 2; i*i <= x; i++) {
48         while (x % i == 0) {
49             res ~= i;
50             x /= i;
51         }
52     }
53     if (x > 1) res ~= x;
54     // res is sorted!
55     return res;
56 }
57 
58 ///
59 unittest {
60     import std.range, std.algorithm;
61     assert(equal(factorList(1), new int[0]));
62     assert(equal(factorList(2), [2]));
63     assert(equal(factorList(4), [2, 2]));
64     assert(equal(factorList(24), [2, 2, 2, 3]));
65 }
66 
67 import dkh.numeric.primitive;
68 
69 /// Millar-Rabin Test
70 bool isPrime(ulong n) {
71     import dkh.int128;
72     if (n <= 1) return false;
73     if (n == 2) return true;
74     if (n % 2 == 0) return false;
75     ulong d = n-1;
76     while (d % 2 == 0) d /= 2;
77     ulong[] alist = [2,3,5,7,11,13,17,19,23,29,31,37];
78     foreach (a; alist) {
79         if (n <= a) break;
80         ulong y = ulongPowMod(a, d, n);
81         ulong t = d;
82         while (t != n-1 && y != 1 && y != n-1) {
83             y = mul128(y, y).mod128(n);
84             t <<= 1;
85         }
86         if (y != n-1 && t % 2 == 0) {
87             return false;
88         }
89     }
90     return true;
91 }
92 
93 ///
94 unittest {
95     assert(!isPrime(0));
96     assert(!isPrime(1));
97     assert(isPrime(2));
98     assert(isPrime(10^^9 + 7));
99 }