我用C sharp编写了一个Miller Rabin素数测试,但是每次输入都会返回false。
以下是代码:
static Boolean MilRab(UInt64 n)
{
UInt64[] ar = new UInt64[] { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
for (int i = 0; i < 10; i++)
{
if (Tanu(ar[i], n) == true) return false;
}
return true;
}//MilRab
static Boolean Tanu(UInt64 a, UInt64 n)
{
UInt64 b = n - 1;
UInt64 d = 1;
UInt64 x;
Int16 i;
for (i = 63; i >= 0; i--) if (((b >> i) & 1) == 1) break;
for (;i>=0;i--)
{
x = d;
d = ((d * d) % n);
if (d == 1 && x != 1 && x != n - 1) return true;
if (b>>i == 1) d = (d * a) % n;
}
if (d != 1) return true;
return false;
}//Tanu
您认为问题是什么?我花了一天时间进行调试,这让我很疯狂。谢谢。
答案 0 :(得分:3)
检查int和BigInteger
的此实现http://rosettacode.org/wiki/Miller-Rabin_primality_test#C.23
答案 1 :(得分:2)
正如阿米尔所说,
http://rosettacode.org/wiki/Miller-Rabin_primality_test#C.23
有解决方案。但是..我试过它,即使对于非常小的输入值,如79,它也会给出错误的结果(79是素数,但是反复出现而不是素数)。原因是功率溢出(例如11 ^ 78类似于1E + 81,无法用32或64位整数表示)。
所以这里
public static class RabinMiller
{
public static bool IsPrime(int n, int k)
{
if(n < 2)
{
return false;
}
if(n != 2 && n % 2 == 0)
{
return false;
}
int s = n - 1;
while(s % 2 == 0)
{
s >>= 1;
}
Random r = new Random();
for (int i = 0; i < k; i++)
{
double a = r.Next((int)n - 1) + 1;
int temp = s;
int mod = (int)Math.Pow(a, (double)temp) % n;
while(temp != n - 1 && mod != 1 && mod != n - 1)
{
mod = (mod * mod) % n;
temp = temp * 2;
}
if(mod != n - 1 && temp % 2 == 0)
{
return false;
}
}
return true;
}
}
你应该添加一个功能
static int ModuloPower(int a, int b, int n)
{
// return (a^b)%n
int res = 1;
for (int i = 0; i < b; ++i)
res = (res * a) % n;
return res;
}
并将power / modulo行更改为
int mod = ModuloPower(a, temp, n); // (int)Math.Pow(a, (double)temp) % n;
这当然可以再次优化..请参阅rosettacode网站上其他语言的代码示例,以获得更快速计算功率/模数的更聪明方法。
(我尝试在那里编辑代码,但必须注册,所以我在这里发帖。)