素數,不能被除了1和本身以外整除的數被稱為素數。接下來我用三種方式求得1~100以內素數。
方式一
外層每循環一次,內層就計算出這個數有幾個因子,我們都知道素數的因子只有兩個,所以如果個數為2就加進總和里面:
package day_11_25;
/** * 計算1-100之間的素數和 * * @author soberw */
public class PrimeFor {
public static void main(String[] args) {
//記錄和
int sum = 0;
//記錄因子個數
int count = 0;
int counter = 0;
for (int i = 2; i <= 100; i++) {
//初始置0
count = 0;
for (int j = 1; j <= i; j++) {
counter++;
if (i % j == 0) {
count++;
}
}
//兩個因子為素數
if (count == 2) {
sum += i;
}
}
System.out.println("總和為" + sum);
System.out.println("循環了" + counter + "次");
}
}
運行結果:

共計算了5049次。
方式二
方式一雖然好理解,但是也存在很多的問題,比如如果一個數他本來就是偶數(當然除了2),那就沒有判斷的必要了,也還有就是沒有中斷條件,就算已經知道了這個數不是素數了,但程序還是從頭到尾循環了一遍,於是我做了改進,加入了互斥鎖,並且從2開始計算(因為最小素數為2),實現如下:
package day_11_25;
/** * 計算1-100之間的素數和 * * @author soberw */
public class PrimeFor2 {
public static void main(String[] args) {
int sum = 0;
//聲明互斥鎖
boolean flag = true;
int counter = 0;
for (int i = 2; i <= 100; i++) {
flag = true;
//偶數直接跳到下一次
if (i != 2 && i % 2 == 0){
continue;
}
//從2到除了它本身的數之間判斷
for (int j = 2; j < i; j++) {
counter++;
//有因子直接退出
if (i % j == 0) {
flag = false;
break;
}
}
if (flag) {
sum += i;
}
}
System.out.println("總和為" + sum);
System.out.println("循環了" + counter + "次");
}
}
運行結果:

相比於第一種方法確實快了不少,共計算了1084次。
方式三
那么有沒有更好的方法呢,答案是肯定的,我們在判斷的時候,都是從頭到尾去循環一遍,就算是加了互斥鎖,也要一次加一個去判斷,有點繁瑣。
那有沒有更好的解決方式呢,於是我就想到了下面這種方法,通過開平方判斷。打個比方,如果我們要判斷100是不是素數,就首先確定一個中間數,你可以找到100的根(10),將數分成兩份,如圖:

圖可能畫的有點抽象,其實就是我們將10作為中間數,10前面的數乘以10后面的數如果有出現等於100的情況,那就不是素數(比如2x50=100)。
因為因子都是成對存在的,1和100,2和50,4和25,5和20,10和10。成對的因子,其中一個必然小於等於100的開平方,另一個大於等於100的開平方。所以這樣一來我們就最多判斷10次就行了,一下子減少了90次。效率成倍提高。而且實現起來也不復雜,如下:
package day_11_25;
/** * 計算1-100之間的素數和 * * @author soberw */
public class PrimeFor3 {
public static void main(String[] args) {
int sum = 0;
int counter = 0;
label:
for (int i = 2; i <= 100; i++) {
if (i != 2 && i % 2 == 0) {
continue;
}
for (int j = 2; j <= Math.sqrt(i); j++) {
counter++;
if (i % j == 0) {
continue label;
}
}
sum += i;
}
System.out.println(sum);
System.out.println(counter);
}
}
運行結果:

僅僅計算了187次,相比於前兩種方法,大大的提高了效率。
