在前面的章节中,我们分别讨论了质数和指数,今天我们不做其他的,仅仅将它们进行整合一下,为什么呢?因为在数学领域,有一种特殊的正整数,形如:2^p - 1,其中指数p为质数,这种数字被称为梅森数,其中的质数又被称为梅森素数。

梅森数中有一种“变体”——伪素数:2^(p-1)-1,它能被p整除,同时p又为非偶数的合数。

OK,今天我们用JAVA语言来针对这几个特殊数字进行编译。

一、梅森数

我们先根据梅森数的公式自定一个方法用以计算梅森数:

/**
* 计算梅森数
*
* @param number
* @return
*/
private static BigDecimal calculateMersenneNumber(BigDecimal number) {
// TODO Auto-generated method stub
return integerMi(BigDecimal.valueOf(2), number).subtract(BigDecimal.ONE);
}
上述这个方法仅仅是用以计算2^p - 1的结果,因此我们在main()方法体中编译代码时需要“提取”质指数:
for (BigDecimal a = BigDecimal.valueOf(2); a.compareTo(BigDecimal.valueOf(100)) <= 0; a = a.add(BigDecimal.ONE))
if (primeNumber(a))
System.out.println("2 ^ " + a + " - 1 = " + calculateMersenneNumber(a));
运行结果:
2 ^ 2 - 1 = 3
2 ^ 3 - 1 = 7
2 ^ 5 - 1 = 31
2 ^ 7 - 1 = 127
2 ^ 11 - 1 = 2047
2 ^ 13 - 1 = 8191
2 ^ 17 - 1 = 131071
2 ^ 19 - 1 = 524287
2 ^ 23 - 1 = 8388607
2 ^ 29 - 1 = 536870911
2 ^ 31 - 1 = 2147483647
2 ^ 37 - 1 = 137438953471
2 ^ 41 - 1 = 2199023255551
2 ^ 43 - 1 = 8796093022207
2 ^ 47 - 1 = 140737488355327
2 ^ 53 - 1 = 9007199254740991
2 ^ 59 - 1 = 576460752303423487
2 ^ 61 - 1 = 2305843009213693951
2 ^ 67 - 1 = 147573952589676412927
2 ^ 71 - 1 = 2361183241434822606847
2 ^ 73 - 1 = 9444732965739290427391
2 ^ 79 - 1 = 604462909807314587353087
2 ^ 83 - 1 = 9671406556917033397649407
2 ^ 89 - 1 = 618970019642690137449562111
2 ^ 97 - 1 = 158456325028528675187087900671

根据梅森数的定义我们计算出了指数p在前100以内的所有梅森数。

二、梅森素数

梅森素数也是梅森数,只不过它将“梅森合数”舍弃了,因此我们在输出梅森素数时只需在main()方法体中梅森数的源代码中加入一个条件语句,用以限制输出时只输出梅森素数即可。

for (BigDecimal a = BigDecimal.valueOf(2); a.compareTo(BigDecimal.valueOf(100)) <= 0; a = a.add(BigDecimal.ONE))
if (primeNumber(a) && primeNumber(calculateMersenneNumber(a)))
System.out.println("2 ^ " + a + " - 1 = " + calculateMersenneNumber(a));
运行结果:
2 ^ 2 - 1 = 3
2 ^ 3 - 1 = 7
2 ^ 5 - 1 = 31
2 ^ 7 - 1 = 127
2 ^ 13 - 1 = 8191
2 ^ 17 - 1 = 131071
2 ^ 19 - 1 = 524287
…………………………
它得先计算,在判断是否为素数,运行时间相当长,因此我只选取了指数在20以内的。
三、伪素数
同样,我们先根据伪素数的公式自定一个方法用以计算伪素数:
/**
* 计算伪素数
*
* @param number
* @return
*/
private static BigDecimal calculatePseudoPrimeNumber(BigDecimal number) {
// TODO Auto-generated method stub
return integerMi(BigDecimal.valueOf(2), number.subtract(BigDecimal.ONE)).subtract(BigDecimal.ONE);
}

就如同上述计算梅森数和梅森素数一样,在编译main()方法体中的代码时,我们也需要根据伪素数的定义对2的指数进行一定的限制;并且我们多加一个步骤,就是对其进行质数分解。

为此我们编译出了如下代码:

for (BigDecimal a = BigDecimal.valueOf(2);; a = a.add(BigDecimal.ONE))
if (calculatePseudoPrimeNumber(a).remainder(a).equals(BigDecimal.ZERO) && !primeNumber(a)
&& a.remainder(BigDecimal.valueOf(2)).equals(BigDecimal.ONE)) {
System.out.print("2 ^ ( " + a + " - 1 ) - 1 | " + a + " = ");
divisorPrime(a);
System.out.println();
}

PS:我们看伪素数的公式:2^(p-1)-1能被p整除,最小的伪素数为341,那么带入公式,其输出的结果也是非常大的,因此我们在此省却此类结果的输出,仅仅用公式表达伪素数的含义,并且对伪素数进行质数分解。

运行结果:

2 ^ ( 341 - 1 ) - 1 | 341 = 11 * 31
2 ^ ( 561 - 1 ) - 1 | 561 = 3 * 11 * 17
2 ^ ( 645 - 1 ) - 1 | 645 = 3 * 5 * 43
2 ^ ( 1105 - 1 ) - 1 | 1105 = 5 * 13 * 17
2 ^ ( 1387 - 1 ) - 1 | 1387 = 19 * 73
2 ^ ( 1729 - 1 ) - 1 | 1729 = 7 * 13 * 19
2 ^ ( 1905 - 1 ) - 1 | 1905 = 3 * 5 * 127
2 ^ ( 2047 - 1 ) - 1 | 2047 = 23 * 89
2 ^ ( 2465 - 1 ) - 1 | 2465 = 5 * 17 * 29
2 ^ ( 2701 - 1 ) - 1 | 2701 = 37 * 73
2 ^ ( 2821 - 1 ) - 1 | 2821 = 7 * 13 * 31
………………………………

PS:“|”代表前者可以被后者整除。