我必须编写一个简单的程序来打印从2到100的素数。
首先,我做了一些关于质数是什么的研究。我试了很长时间,最后我在书中找到了答案,因为每次写100%工作代码时我都没有成功。
我理解大部分答案代码,但有一部分我不明白。让我试着解释一下。首先是这本书中的代码:
// Find prime numbers between 2 and 100.
class Prime {
public static void main(String args[]) {
int i, j;
boolean isprime;
for(i=2; i < 100; i++) {
isprime = true;
// see if the number is evenly divisible
for(j=2; j < i/j; j++)
// if it is, then it's not prime
if((i%j) == 0) isprime = false;
if(isprime)
System.out.println(i + " is prime.");
}
}
}
好的,所以我知道这一点:素数只能由它自己和1来分割。
让我先取4号,这不是素数,因为它也可以除以2.所以在代码中我遵循for循环,但是我被困在'看看数字是否可以被整除'部分。在4的情况下,4%4
没有余数,因为==0
部分它是假的。
因此isprime
为假。但是,我读错了或者想错了,因为如果拿一个素数,比如5,我会得到相同的结果:5%5
没有余数,因为5/5 == 1
。因此,在这种情况下,5%5
也等于0
,因此isprime
也应该为false,但在这种情况下,数字5是素数。
所以我真的不明白这项检查在代码中是如何工作的。
在开头i
是2而j
是2,所以你得2%2
,也没有余数,但2也是素数,所以我知道我看到它错了。
如果有人可以解释这是如何运作的,我在网上搜索了一个小时但却找不到它。
答案 0 :(得分:1)
首先,应该说 - 在其他答案中已经提到过 - 你从书中得到的代码是错误的(或者你错过了复制它)。内部循环的条件应该是
for(j=2; j <= i/j; j++)
这样做的一个重要教训是,您必须尝试运行书籍示例,看看它们是否有效。如果你运行它,你会看到它标记为4,9,25,49为素数,而不是。
但您对代码的阅读也不正确。你说4被判断为不是素数因为4%4 == 0
。但事实上,一个素数被允许自己整数(任何数字都是)。事实上,通过将素数除以自身来测试素数是行不通的。
让我们看看这是什么。你了解外部循环 - 它给你的候选人测试他们是否是素数。
然后它的工作方式如下:假设当前候选人是素数。尽量用所有可能的除数除以它。如果任何除数均分,则将其标记为&#34;而不是素数&#34;。
如果在对所有可能的除数进行测试之后,没有一个达到标记为&#34;而不是素数&#34;,那么它确实是素数并且你可以打印它。
因此i
循环代表候选者,j
循环代表潜在的除数。以15
为例{@ 1}}。
i
开始j
i/j
即15/2
,因此我们进入循环。
2 < 7
现在是j
。 3
为i/j
,15/3
。 5
,所以我们继续。
3 < 5
。isprime=false
现在是j
。 4
为i/j
,15/4
。 3
false ,因此我们停止。正如您所看到的,上面4 < 3
j=3
设置为isprime
的步骤为false
,因此我们不打印它 - 它不是素数。
现在让我们采用一个真正的素数,如13:
j
i/j
开始13/2
,2 < 6
即6. j
,因此我们进入循环。
3
现在是i/j
。 13/3
为4
,3 < 4
。 j
,所以我们继续。
4
现在是i/j
。 13/4
为3
,4 < 3
。 isprime
false ,因此我们停止。没有将false
设置为true
的步骤。它仍然是j
,因此数字13是素数,我们打印它。
现在,这里的诀窍是我们为i
提供哪些候选人。天真地,第一次写这篇文章的人会认为候选人应该是1和1
之间的所有数字,不包括i
和for ( j = 2; j < i; j++ )
。所以他们会编写一个循环:
15 = 3 x 5
但这很浪费。为什么?假设您检查了数字15.您发现3是它的除数。那个怎么样?因为5
。但这意味着5
也是一个除数。你不需要测试除数,如果除以它,你得到一个你已经测试过的除数。因此,无需测试3
,因为我们已经测试了for ( j = 2; j <= i / 2; j++ )
。
所以,再一次,天真的程序员可能会决定我们只能测试一半的候选人:
i
但事实上,从数学上讲,这仍然是浪费。实际上,我们应该只达到j
的平方根。为什么?因为如果除数i
大于j x k = i
的平方根,那么k
,则i
将小于k
的平方根。如果j x k
更大,那么sqrt(i) x sqrt(i)
将大于j x k > i
,这意味着他们i
。但我们知道它们等于i
!
这意味着如果潜在的除数大于i
的平方根,我们已经找到了另一个除数,小于i
的平方根,并对其进行了测试并标记为{{ 1}} as&#34; not prime&#34;。
这就是你的候选循环测试的内容。它基本上是一种简单的写作方式
for ( j = 2; j <= Math.sqrt(i); j++ )
不调用Math
类而不将整数转换为双精度。
但正如我从一开始就说的,条件是<=
而不是<
非常重要。对于素数的平方数,(4 = 2 x 2,9 = 3 x 3),唯一合适的除数是等于到它们的平方根的数字。
最后一点注意:这本书的例子仍然很浪费,因为在找到一个使数字不是素数的除数后它不会停止检查。找到一个除数就足够了。一种方法是更改循环条件,如下所示:
for ( j = 2; isprime && j <= i/j; j++ )
所以只要我们仍然有理由相信这个数字是素数,那么循环才会继续。在将j
标记为isprime
的{{1}}后,循环将自动停止。
(当然,这个算法不是最好的算法。有更好的算法。它只是每个人开始的算法。)
评论中提出的问题的答案:
内循环总是重新执行。可以这样想:
如果循环显示:
false
它相当于
for ( int i = 0; i < 3; i++ ) {
doSomething();
}
所以如果&#34;做某事&#34; part本身就是一个循环:
doSomething();
doSomething();
doSomething();
相当于:
for ( int i = 0; i < 3; i++ ) {
for ( int j = 0; j < 2; j++ ) {
runSomething();
}
}
所以你看,每次它都是从零开始的新for ( int j = 0; j < 2; j++ ) {
runSomething();
}
for ( int j = 0; j < 2; j++ ) {
runSomething();
}
for ( int j = 0; j < 2; j++ ) {
runSomething();
}
。
关于花括号的问题:正式,j
语句的格式为:
for
该语句可以是单个语句,如方法调用,内部for循环,if语句或其他内容。在这种情况下,它不需要大括号。或者语句可以是块,它是一对包含零个或多个语句的大括号。您习惯于看到一个块,实际上它建议始终使用块而不是单个语句,因为它更容易添加语句。
答案 1 :(得分:0)
你的内循环标题中有一个小错误。
// ...
for(j=2; j <= i/j; j++)
// ...
因此,您必须使用<
而不是<=
。
答案 2 :(得分:0)
尝试理解这一点的最佳方法是将System.out.println放入循环中,其值为i,j。
我为你做了,2,3,4和5.(只有4不是素数)。
i = 2 - &gt; 循环的条件是2&lt; 2/2是假的,你不会进入循环,它是素数。
i = 3 - &gt; 循环的条件是2&lt; 3/2是假的,你不进入循环,它是素数。
i = 4 - &gt; 循环的条件是2&lt; 4/2是假的,你不进入循环并且它是素数。也许循环条件应该是&lt; =
i = 5 - &gt; 循环的条件是2&lt; 5/2为真,你进入循环,if条件为false,你将1添加到j并执行循环: 3&lt; 5/3是假的,你不会进入循环,它是素数。
答案 3 :(得分:0)
您的问题出现在第二个for循环中
for(j=2; j < i/j; j++)
对于4及以下,控件永远不会进入内部for循环,并且在开始检查之前你已经假设你的数字是素数,所以如果控制从不进入循环,它将被视为素数。
条件应该是:
for(j=2; j <= i/j; j++)
这会给你正确的结果。
答案 4 :(得分:0)
我刚刚完成了同样的问题。虽然最后花了几个小时,但我强迫自己不要在问题之前的任何地方寻找答案。我仍然不知道书中的解决方案是什么。我的观点是试图通过恶化来对抗,审查手头的材料,你就会得到它。这是我的代码,丑陋而又情感。
class primeNum {
public static void main(String args[]){
int x = 2;
int y = 2;
int count;
System.out.println("The prime numbers between 2 and 100 are: ");
while (x < 100) {
count = 0;
y = 2;
while (y <= x) {
if (x % y == 0) {
count ++;
}
++y;
}
if (count == 1 ) {
System.out.println(" " + x);
}
++x;
}
}
}