我试图弄清楚这个Java方法如何计算素数,但有些事让我感到困惑。
public static boolean isPrime(int number){
for(int divisor =2; divisor <= number / 2; divisor++){
if (number % divisor ==0){
return false;
}
}
return true;
}
正如您在for循环的第二行中看到的那样,它显示divisor <= number /2
而不是divisor <= number
。谁能告诉我原因呢?
答案 0 :(得分:7)
首先,如果你放divisor <= number
,你就不会得到素数,因为每个数字都可以自行整除。如果循环在divisor
变为number
之前没有退出,您将进入
number % divisor == 0
条件,并返回false
。
无论是谁写了这段代码,都会发现你可以在达到一半的数量后立即停止,因为如果你在(2..number/2)
的下半部分没有找到除数,那么上面就没有除数这个数字的一半,所以你可以声明数字素数,而不会尝试其他候选除数,但不成功。
但是,这不是你能做的最好的事情:可以使用更强的条件 - 你可以将divisor
与number
的平方根进行比较。这是有效的,因为如果你没有一个小于或等于数字平方根的除数,那么平方根上面也不会有除数(考虑为什么这样做是个好主意) )。
int stop = Math.sqrt(number);
for(int divisor = 2; divisor <= stop ; divisor++) {
...
}
答案 1 :(得分:3)
原因是任何数字都不能除以任何大于它的半数的除数,并且给出多于1(如果我们说的是整数,当然)。
答案 2 :(得分:2)
任何数字都不能被一半以上的数字整除。
例如,最后一个数字10可以被整除为5. 10不能被6,7,8或9整除。
这就是为什么消除明显的不匹配以提高算法性能的原因。
答案 3 :(得分:1)
正如其他人所指出的,没有n大于n / 2的因素。一个更好的解决方案是将迭代变量与n的平方根进行比较,就好像没有小于或等于平方根的因子一样,不能有任何大于平方根(注意它比较有效率) i * i&lt; = n,我&lt; = Math.sqrt(n))。
更好的方法是AKS素性测试。如果数字是2或3,那么它显然必须是素数。否则,它可以以(6k + i)形式重写,其中i = -1,0,1,2,3,4。任何(6k + 2)或(6k + 4)可被2整除,并且任何( 6k + 3)可被3整除,因此素数必须采用(6k - 1)或(6k + 1)形式。
public static boolean isPrime(long n) {
/* This code uses the AKS primality test
* http://en.wikipedia.org/wiki/AKS_primality_test
*/
if (n <= 3) return n > 1;
if (n % 2 == 0 || n % 3 == 0) return false;
for (int i = 5; i*i <=n; i+=6) {
if (n % i == 0 || n % (i+2) == 0) return false;
}
return true;
}
}
我在Sedgewick的Java编程简介(虽然这是在引入方法之前的第一章)中将此作为我PrimeCounter
问题解决方案的一部分。
public class PrimeCounter {
public static void main(String[] args) {
long n = 10000000;
long count = 0;
for (long i = 0; i <= n; i++) {
if (isPrime(i)) count++;
}
System.out.println("The number of primes less than "
+ n + " is " + count);
}
public static boolean isPrime(long n) {
/* This code uses the AKS primality test
* http://en.wikipedia.org/wiki/AKS_primality_test
*/
if (n <= 3) return n > 1;
if (n % 2 == 0 || n % 3 == 0) return false;
for (int i = 5; i*i <=n; i+=6) {
if (n % i == 0 || n % (i+2) == 0) return false;
}
return true;
}
}
答案 4 :(得分:0)
它使用的事实是,如果其中一个因子大于N / 2,则另一个因子必须小于2.
事实上,通过使用平方根可以获得大量(渐近)增益。
那是因为如果一个因子大于平方根,另一个因子就更少了。
抱歉Sebri Zouhaier。我正在改变效忠。 +1不是必需的,所以最佳答案如下。 我很抱歉为了这么微小的改进而改变立场!
答案 5 :(得分:0)
数字 N 不能有任何除数 D <> N / 2和&lt; 名词的。要看到这一点,请注意,如果 D 是 N 的除数,那么它必须等于 N / D < sub> 2 表示某些 D 2 。所以 N 的除数是这个序列的整数值: N , N / 2, N / 3,......这是一个降序。很明显, N 和 N / 2之间不存在任何除数。
事实上,检查primality的程序在sqrt( N )而不是 N / 2处停止是很常见的。原因是:假设存在除数 D ,使得 D &gt; SQRT(名词的)。那么 N / D = D 2 也必须是 N 的除数。并且必须是 D 2 &lt; sqrt( N ),因为如果 D 和 D 2 都是&gt; sqrt( N ),然后 D * D 2 必须是&gt; N ,这是错误的,因为 D * D 2 = N 。这意味着无需检查可能的除数 D &gt; SQRT(名词的);如果存在这样的除数,我们已经在循环的早期找到 D 2 并证明 N 不是素数。
答案 6 :(得分:0)
对上述一些答案的一个小警告是0和1不是素数。您可以使用诸如
之类的实现来解释这个(对于正整数)public static boolean isPrime(int number){
if (number == 0 || number == 1)
return false;
else
{
int stop = (int) Math.sqrt(number);
for (int divisor = 2; divisor <= stop ; divisor++)
{
if (number % divisor ==0)
return false;
}
return true;
}
}
答案 7 :(得分:-1)
public static Boolean isPrime(int num){ //method signature. returns Boolean, true if number isPrime, false if not
if(num==2){ //for case num=2, function returns true. detailed explanation underneath
return(true);
}
for(int i=2;i<=(int)Math.sqrt(num)+1;i++){ //loops through 2 to sqrt(num). All you need to check- efficient
if(num%i==0){ //if a divisor is found, its not prime. returns false
return(false);
}
}
return(true); //if all cases don't divide num, it is prime.
}
// Returns true iff n is prime. First checks if n is even, handling the
// cases of n=2 (prime) or n is even > 2 (not prime). Then checks if any
// odd #'s between 3 and sqrt(n), inclusive, are divisors of n, returning
// false if any are.
public static boolean isPrime(int n) {
if (n < 2) return false;
if (n % 2 == 0)
// n is an even, so return true iff n is exactly 2
return (n == 2);
for (int i=3; i*i<=n; i+=2)
if (n % i == 0)
// i divides evenly into n, so n is not prime
return false;
return true;
}