当用户输入偶数 n 的时候,就要从 2 开始(2 是最小的质数),到这个 n / 2 的一半结束(这个数字的一
半是最大的拆分可能)一个一个的去实验,看看被拆分的两个数字是不是质数,如果是,就输出它们的结果。
代码如下:
//判断数字是否是质数
function isPrimeNumber(a){
for(var i = 2 ; i < a ; i++){
if(a % i == 0) return false;
}
return true;
}
//用户输入一个数字
var n = parseInt(prompt("请输入一个偶数"));
//拆分验证是不是都是质数
for(var i = 2 ; i <= n / 2 ; i++){
if(isPrimeNumber(i) && isPrimeNumber(n - i)){
console.log("偶数" + n + "可以拆分为质数" + i + "+" + (n - i));
}
}
运行程序,我们用一个较大的数字进行测试。在弹出的输入框中输入 8848,点击确定之后,发现控制台输
出了 8848 所有可以被拆分为质数和的形式
案例描述
如果 2 p - 1 恰好是个质数(p 为任意正数),则这个质数就称为梅森素数。请编写程序,找出前 6 个梅森
素数。
例如质数 3 就是最小的梅森素数,因为它可以写为 2 2 - 1。下一个梅森素数是 7,因为它可以写为 2 3 - 1。
但是 2 4 - 1 的值是 15,它不是质数,那更不是梅森素数了。
案例分析
题目的要求是寻找前 6 个梅森素数,正确的算法思路是:从 1 开始,依次将正整数 p 带入公式 2 p - 1,检
测 2 p - 1 的值是不是质数,如果是,则说明此数是梅森素数。
和上一小节我们讲解的“哥德巴赫猜想”一样,我们这里又需要检测某一个函数是不是质数的功能。此时可以直接使用上一小节书写的 isPrimeNumber 函数。这就是函数的优势:只需要写一次,就可以多次调用,服务
于不同的业务。
我们直接复制粘贴上一小节的函数,注意,这并不是“偷懒”,而是“站在巨人的肩膀上”,我们并不需要
“重复的造轮子”:
//判断数字是否是质数
function isPrimeNumber(a){
for(var i = 2 ; i < a ; i++){
if(a % i == 0) return false;
}
return true;
}
接下来需要做的就是从 1 开始,带入公式 2 p - 1,然后检测 2 p - 1 的值是不是质数。题目要求我们输出前
30 个梅森素数,由于我们并不知道 p 到多少的时候,能产生 6 个梅森素数,所以,使用 while(true)循环是非
常适合的。
案例代码
案例代码如下:
//判断数字是否是质数
function isPrimeNumber(a){
//统计 a 的约数个数
for(var i = 1 , count = 0; i <= a ; i++){
if(a % i == 0){
count ++;
}
}
//如果仅有 2 个因数,表示这个数字是质数,反之不是。
return count == 2;
}
//计数器,统计已经发现的梅森素数的个数
var count = 0;
var p = 1;
var m;
while(true){
//计算 2^p - 1
m = Math.pow(2 , p) - 1;
if(isPrimeNumber(m)){
console.log("质数" + m + "是梅森素数,它可以表示为 2^" + p + "-1");
//计数器加 1
count++;
if(count == 6){
break;
}
}
//测试下一个 p
p++;
}
从输出结果可以看出,梅森素数 2 p - 1 中的 p 一定是质数,比如前 6 个梅森素数的 p 分别是 2、3、5、7、
13、17,它们都是质数。但是反之,当 p 是素数时 2 p - 1 却未必是素数。比如素数 11,2 11 - 1 等于 2047。而
2047 不是素数,因为它可以表示成为 23 * 89。再比如素数 23,223 - 1 等于 8388607,它不是素数,因为可
以表示为 47 * 178481。
正因如此,梅森素数非常稀少,利于超级计算机,目前人类仅发现 50 个梅森素数,其中最大的是 2 77232917 -1
(即 2 的 77232917 次方减 1),它有 23249425 位数,注意,不是这个数等于 23249425,而是它有 23249425
位,真的是天文数字!
本例使用了和“哥德巴赫猜想”同样的一个函数 isPrimeNumber,更加能体现函数“书写一次,多次调用”
的特点,简化了程序的书写。