Miller-Rabin Test
参考wiki—— https://en.wikipedia.org/wiki/Miller–Rabin_primality_test
其中a的选择:
所以base可以查表,当n不够大时:
private static readonly uint[][] TEST_BASE =
{
new uint[] { 2 },
new uint[] { 2, 3 },
new uint[] { 31, 73},
new uint[] { 2, 3, 5},
new uint[] { 2, 3, 5, 7},
new uint[] { 2, 7, 61},
new uint[] { 2, 13, 23, 1662803},
new uint[] { 2, 3, 5, 7, 11},
new uint[] { 2, 3, 5, 7, 13},
new uint[] { 2, 3, 5, 7, 17},
new uint[] { 2, 3, 5, 7, 11, 13, 17, 19, 23},
new uint[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37},
new uint[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37},
new uint[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41},
};
private static readonly double[] TEST_THREADHOLD =
{
1024d, 1373653d, 9080191d, 25326001d, 3215031751d, 4759123141d,
1122004669633d, 2152302898747d, 3474749660383d, 341550071728321d,
3825123056546413051d, 18446744073709551616d,
318665857834031151167461d, 3317044064679887385961981d
};
将上述代码转为c#
/// <summary>
/// 米勒拉宾检测法。如果<paramref name="n"/>为素数返回true,否则返回false。
/// </summary>
public static bool MillerRabinTest(int n)
{
if (n < 2) return false;
if (n == 2) return true;
if (IsEven(n)) return false;
//n - 1 = 2^s * r
var nMinusOne = (uint)(n - 1);
var s = nMinusOne.NumberOfTrailingZeros();
var r = nMinusOne >> s;
var index = 0;
while (n >= TEST_THREADHOLD[index]) ++index;
var allbase = TEST_BASE.Skip(index).Take(1).SelectMany(array => array).ToArray();
foreach(var @base in allbase)
{
var mp = MonModPow(@base, r, (uint)n);
if (mp != 1 && mp != nMinusOne)
{
for(var i = 1; i <= s - 1 && mp != nMinusOne; ++i)
{
mp = MonModPow(mp, 2, (uint)n);
if (mp == 1) return false;
}
if (mp != nMinusOne) return false;
}
}
return true;
}
/// <summary>
/// <paramref name="n"/>二进制尾数0的个数
/// </summary>
public static int NumberOfTrailingZeros(this int n)
{
if (n == 0) return 32;
var c = 31;
var t = n << 16; if (t != 0) { c -= 16; n = t; }
t = n << 8; if (t != 0) { c -= 8; n = t; }
t = n << 4; if (t != 0) { c -= 4; n = t; }
t = n << 2; if (t != 0) { c -= 2; n = t; }
t = n << 1; if (t != 0) { c -= 1; }
return c;
}
private static bool IsEven(int n) => (n & 1) == 0;
其中
public static uint MonModPow(uint value, uint exponent, uint modulo)