实施费马小定理的问题

时间:2012-12-27 22:25:07

标签: java primes

这是我对费马小定理的实现。有谁知道为什么它不起作用?

以下是我遵循的规则:

  • 设n为测试素数的数字。
  • 选择介于2和n-1之间的任何整数。
  • 计算a ^ n mod n。
  • 检查是否a ^ n = a mod n。

mycode的:

int low = 2;
int high = n -1;
Random rand = new Random();

//Pick any integer a between 2 and n-1.
Double a = (double) (rand.nextInt(high-low) + low);

//compute:a^n = a mod n
Double val = Math.pow(a,n) % n;

//check whether a^n = a mod n   
if(a.equals(val)){
return "True";
}else{
return "False";
}

这是一个小于100000的素数列表。每当我输入任何这些数字,而不是得到'真',我得到'假'。

The First 100,008 Primes

这就是我认为代码无效的原因。

3 个答案:

答案 0 :(得分:1)

在java中,double只有大约15到17位数的有限精度。这意味着虽然您可以计算Math.pow(a,n)的值,但对于非常大的数字,您无法保证一旦值超过15位,您将获得准确的结果。

使用较大的a或n值时,您的计算将超出该限制。例如 Math.pow(3, 67)的值为9.270946314789783e31,这意味着最后3位之后的任何数字都会丢失。因此,在应用模运算后,您无法保证获得正确的结果(example)。

这意味着您的代码实际上并未测试您的想法。这是浮点数工作方式所固有的,您必须更改保持值以解决此问题的方式。你可以使用long,但是你会遇到溢出问题(长期不能保持大于2^64 - 1的值,所以再次,3^67你会遇到另一个问题。< / p>

一种解决方案是使用一个用于保存任意大数字的类,例如BigInteger的{​​{1}}。

答案 1 :(得分:1)

正如其他人所说,取力会迅速溢出。例如,如果你选择数字n来测试小到30的素数,并且随机数a是20,20 ^ 30 =大约10 ^ 39这是&gt;&gt; 2 ^ 90。 (我拿了10 ^ 39的ln。)

您想使用BigInteger,它甚至拥有您想要的确切方法:

public BigInteger modPow(BigInteger exponent, BigInteger m)

“返回一个BigInteger,其值为(this ^ exponent mod m)”

另外,我认为测试2和n-1之间的单个随机数不会“证明”任何东西。你必须循环遍历2和n-1之间的所有整数。

答案 2 :(得分:1)

@evthim即使您已经使用BigInteger类的modPow函数,也无法获得正确选择范围内的所有素数。为了进一步阐明问题,您将获得该范围内的所有质数,但是有些数字不是质数。如果您使用BigInteger类重新排列此代码。当您尝试所有64位数字时,一些非质数也会写入。这些数字如下;

341、561、645、1105、1387、1729、1905、2047、2465、2701、2821、3277、4033、4369、4371、4681、5461、6601,7957、8321、8481、8911、10261、10585 ,11305,12801,13741,13747,13981,14491,15709,15841,16705,18705,18721,19951,23001,23377,25761,29341,... https://oeis.org/a001567

161038、215326、2568226、3020626、7866046、9115426、49699666、143742226、161292286、196116194、209665666、213388066、293974066、336408382、376366、666、566、566、666 2001666066、2138882626、295226706.32200418 。 https://oeis.org/a006935

作为解决方案,请通过下面的链接获取这些号码的列表,以确保您测试的号码不在此列表中。 http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html

C#的解决方案如下。

public static bool IsPrime(ulong number)
{
    return number == 2 
        ? true 
        : (BigInterger.ModPow(2, number, number) == 2 
            ? (number & 1 != 0 && BinarySearchInA001567(number) == false) 
            : false)
}

public static bool BinarySearchInA001567(ulong number)
{
    // Is number in list?
    // todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
    // Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}