我曾尝试为Fermat primality test编写代码,但显然失败了。
所以,如果我理解得很好:如果p
是素数,那么((a^p)-a)%p=0
p%a!=0
。
我的代码似乎没问题,因此很可能我误解了基础知识。我在这里缺少什么?
private bool IsPrime(int candidate)
{
//checking if candidate = 0 || 1 || 2
int a = candidate + 1; //candidate can't be divisor of candidate+1
if ((Math.Pow(a, candidate) - a) % candidate == 0) return true;
return false;
}
答案 0 :(得分:4)
阅读Fermat primality test上的维基百科文章,您必须选择少于的a
而不是您正在测试的候选人,而不是更多。
此外,正如MattW评论的那样,仅测试一个a
将无法给出关于候选人是否为素数的确定答案。在确定某个数字可能是素数之前,您必须测试许多可能的a
s。即便如此,some numbers似乎是素数,但实际上是复合的。
答案 1 :(得分:3)
你正在处理非常大的数字,并试图将它们存储在双精度数中,这只是64位。 双倍会尽力保持你的号码,但你会失去一些准确性。
另一种方法:
请记住,mod运算符可以多次应用,但仍会给出相同的结果。 因此,为避免获得大量数字,您可以在计算功率时应用mod运算符。
类似的东西:
private bool IsPrime(int candidate)
{
//checking if candidate = 0 || 1 || 2
int a = candidate - 1; //candidate can't be divisor of candidate - 1
int result = 1;
for(int i = 0; i < candidate; i++)
{
result = result * a;
//Notice that without the following line,
//this method is essentially the same as your own.
//All this line does is keeps the numbers small and manageable.
result = result % candidate;
}
result -= a;
return result == 0;
}
答案 2 :(得分:3)
您的基本算法是正确的,但如果您想对非重要数字执行此操作,则必须使用比int更大的数据类型。
您不应该以您的方式实现模幂运算,因为中间结果很大。这是模幂运算的平方和乘法算法:
function powerMod(b, e, m)
x := 1
while e > 0
if e%2 == 1
x, e := (x*b)%m, e-1
else b, e := (b*b)%m, e//2
return x
例如,437 ^ 13(mod 1741)= 819.如果使用上面显示的算法,则没有中间结果将大于1740 * 1740 = 3027600.但是如果先执行取幂,则中间结果为437 ^ 13是21196232792890476235164446315006597,您可能想避免。
即便如此,费马测试也不完美。有一些综合数字,即卡迈克尔数字,无论你选择何种见证,都会报告素数。如果你想要更好的东西,请寻找Miller-Rabin测试。我在我的博客上谦虚地推荐使用Prime Numbers编程this essay。