大神们,帮我解决这个问题,直接结贴给分不墨迹,一个关于梅森素数的程序

King* 2020-04-14 07:04:49
package com.meisen;

import java.math.BigInteger;

/**
* @authorADMIN 创建时间:2020/4/13
*/
public class MeiSen {
//不断产生素数n
//判断2^n-1是不是素数,是就拿出来
public boolean isSuShu(BigInteger num) {//传进来一个BigInteger类型的num
if (num.compareTo(new BigInteger("2")) == 0 ? false : true) {//如果num等于2
for (BigInteger i = new BigInteger("2"); i.compareTo(num) < 0 ? true : false; i = i.add(new BigInteger("1"))) {
if (num.mod(i).compareTo(new BigInteger("0")) == 0) {//这个数对2到num-1取模,一旦为0
return false;//返回false,num不是素数
}
}
}
return true;
}

public void meiSen() {
BigInteger bigInteger = new BigInteger("2");
while (true) {
//判断bigInteger是不是素数
if (isSuShu(bigInteger)) {//此时bigInteger是素数,然后计算2的bigInteger次方减一,并判断是否为素数
//计算2的bigInteger次方
//System.out.println("指数n------------------------------------------------> "+bigInteger.toString());
BigInteger bI1 = new BigInteger("2");
for (BigInteger i = new BigInteger("1"); i.compareTo(bigInteger) < 0 ? true : false; i = i.add(new BigInteger("1"))) {
bI1 = bI1.multiply(new BigInteger("2"));
}
//再减一
bI1 = bI1.subtract(new BigInteger("1"));
//判断2^n-1整个是否为素数
long start = System.currentTimeMillis();
if (isSuShu(bI1)) {
System.out.println(bI1.toString() + " 耗时:" + (System.currentTimeMillis() - start) + "ms");
}
}
//bigInteger不是素数
bigInteger = bigInteger.add(new BigInteger("1"));
}
}

public static void main(String[] args) {
MeiSen meiSen = new MeiSen();
meiSen.meiSen();
}
}

代码贴这儿了,跑到第7个数的时候,程序挂住了,问了好几个人,都搞不懂为什么
...全文
177 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
King* 2020-04-15
  • 打赏
  • 举报
回复
引用 3 楼 qybao的回复:
[quote=引用 2 楼 King* 的回复:]

看了下你以前回答过的那个帖子,你说只要n是素数,2的n次方减1就是素数,这个结论恐怕有点问题,2的11次方减1就不是素数,另外,我觉得我这个程序太费时间了,我希望我能尽可能多的跑出更多的梅森素数

网上查了一下,确实有点问题。
2的n次方-1如果是素数,则能推出n一定是素数,可以用反正法
假设2的n次方-1是素数, 而n不是素数,n可以分解成n=p*q
所以 2^n-1=2^(p*q)-1=(2^p-1)*(2^(p*(q-1))+2^(p*(q-2))+...+2^p+1) //(2^p-1)>1, (2^(p*(q-1))+2^(p*(q-2))+...+2^p+1) //(2^p-1)也大于1
说明2^n-1不是素数而是合数,和假设矛盾,所以2的n次方-1是素数,n必然是素数
反之却未必。测试了一下,确实2的11次方-1不是素数。

虽然反之不成立,但也可以利用正推这个规律,2的n次方-1是素数,n必是素数,所以先判断n是不是素数,n是素数之后再判断2的n次方-1是不是,这样应该更高效一些
BigInteger自带判断是否是素数的方法,可以利用该方法试试

public class Sample {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
System.out.printf("n=%d, 2^n-1=%d\n", 2, (1<<2)-1);
for (int n=3; n<5000; n+=2) { //n在5000以内
if (isPNum1(n)) {
if (n < 32) { //int范围内
if (isPNum1((1<<n)-1)) {
System.out.printf("n=%d, 2^n-1=%d\n", n, (1<<n) - 1);
}
//} else if (n < 64) { //long范围内
// if (isPNum2((1L<<n) - 1)) {
// System.out.printf("n=%d, 2^n-1=%d\n", n, (1L<<n) - 1);
// }
} else { //上记范围外
BigInteger b = BigInteger.ONE.shiftLeft(n).subtract(BigInteger.ONE);
if (isPNum3(b)) {
System.out.printf("n=%d, 2^n-1=%s\n", n, b.toString());
}
}
}
}
long t2 = System.currentTimeMillis();
System.out.printf("耗时 %d 毫秒\n", (t2-t1));
}

public static boolean isPNum1(int num) {
if (num==2) return true;
else if (num<2 || num%2==0) return false;
for (int i = 3; i <= Math.sqrt(num); i++)
if (num % i == 0) {
return false;
}
return num>1;
}

public static boolean isPNum2(long num) {
if (num==2) return true;
else if (num<2 || num%2==0) return false;
for (long i = 3; i <= Math.sqrt(num); i++)
if (num % i == 0) {
return false;
}
return true;
}

public static boolean isPNum3(BigInteger b) {
/*
BigInteger two = BigInteger.valueOf(2);
if (b.compareTo(two) == 0) return true;
else if (b.compareTo(two) < 0 || b.mod(two).compareTo(BigInteger.ZERO) == 0) return false;
BigInteger three = BigInteger.valueOf(3);
for (BigInteger i=three; i.compareTo(b.divide(three))<0; i=i.add(two)) {
if (b.mod(i).compareTo(BigInteger.ZERO) == 0) {
return false;
}
}
return true;
*/
return b.isProbablePrime(Integer.MAX_VALUE); //BigInteger自带判断是否是素数的方法
}
}
[/quote] 你这个判断素数的方法确实挺快,比我的快太多了,已结贴给分,感谢
paullbm 2020-04-15
  • 打赏
  • 举报
回复
3楼的代码应该能解决你的问题吧?
qq_39936465 2020-04-15
  • 打赏
  • 举报
回复
引用 楼主 King* 的回复:
代码贴这儿了,跑到第7个数的时候,程序挂住了,问了好几个人,都搞不懂为什么
可能计算量太大了,需要时间反映 第7个 指数19 524287 第8个 指数31 2147483647
qybao 2020-04-14
  • 打赏
  • 举报
回复
引用 2 楼 King* 的回复:
看了下你以前回答过的那个帖子,你说只要n是素数,2的n次方减1就是素数,这个结论恐怕有点问题,2的11次方减1就不是素数,另外,我觉得我这个程序太费时间了,我希望我能尽可能多的跑出更多的梅森素数

网上查了一下,确实有点问题。
2的n次方-1如果是素数,则能推出n一定是素数,可以用反正法
假设2的n次方-1是素数, 而n不是素数,n可以分解成n=p*q
所以 2^n-1=2^(p*q)-1=(2^p-1)*(2^(p*(q-1))+2^(p*(q-2))+...+2^p+1) //(2^p-1)>1, (2^(p*(q-1))+2^(p*(q-2))+...+2^p+1) //(2^p-1)也大于1
说明2^n-1不是素数而是合数,和假设矛盾,所以2的n次方-1是素数,n必然是素数
反之却未必。测试了一下,确实2的11次方-1不是素数。

虽然反之不成立,但也可以利用正推这个规律,2的n次方-1是素数,n必是素数,所以先判断n是不是素数,n是素数之后再判断2的n次方-1是不是,这样应该更高效一些
BigInteger自带判断是否是素数的方法,可以利用该方法试试

public class Sample {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
System.out.printf("n=%d, 2^n-1=%d\n", 2, (1<<2)-1);
for (int n=3; n<5000; n+=2) { //n在5000以内
if (isPNum1(n)) {
if (n < 32) { //int范围内
if (isPNum1((1<<n)-1)) {
System.out.printf("n=%d, 2^n-1=%d\n", n, (1<<n) - 1);
}
//} else if (n < 64) { //long范围内
// if (isPNum2((1L<<n) - 1)) {
// System.out.printf("n=%d, 2^n-1=%d\n", n, (1L<<n) - 1);
// }
} else { //上记范围外
BigInteger b = BigInteger.ONE.shiftLeft(n).subtract(BigInteger.ONE);
if (isPNum3(b)) {
System.out.printf("n=%d, 2^n-1=%s\n", n, b.toString());
}
}
}
}
long t2 = System.currentTimeMillis();
System.out.printf("耗时 %d 毫秒\n", (t2-t1));
}

public static boolean isPNum1(int num) {
if (num==2) return true;
else if (num<2 || num%2==0) return false;
for (int i = 3; i <= Math.sqrt(num); i++)
if (num % i == 0) {
return false;
}
return num>1;
}

public static boolean isPNum2(long num) {
if (num==2) return true;
else if (num<2 || num%2==0) return false;
for (long i = 3; i <= Math.sqrt(num); i++)
if (num % i == 0) {
return false;
}
return true;
}

public static boolean isPNum3(BigInteger b) {
/*
BigInteger two = BigInteger.valueOf(2);
if (b.compareTo(two) == 0) return true;
else if (b.compareTo(two) < 0 || b.mod(two).compareTo(BigInteger.ZERO) == 0) return false;
BigInteger three = BigInteger.valueOf(3);
for (BigInteger i=three; i.compareTo(b.divide(three))<0; i=i.add(two)) {
if (b.mod(i).compareTo(BigInteger.ZERO) == 0) {
return false;
}
}
return true;
*/
return b.isProbablePrime(Integer.MAX_VALUE); //BigInteger自带判断是否是素数的方法
}
}
King* 2020-04-14
  • 打赏
  • 举报
回复
引用 1 楼 qybao的回复:
判断2的n次方-1是不是素数,直接判断n是不是素数就可以了,推导过程看我以前回答的一个帖子
https://ask.csdn.net/questions/1060467
你要找出所有的梅森素数还是什么?

public class Sample {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
for (int n=0; n<100; n++) { //可以调整循环范围
if (isPNum(n)) {
if (n < 32) { //int范围内
System.out.printf("n=%d, 2^n-1=%d\n", n, (1<<n) - 1);
} else if (n < 64) { //long范围内
System.out.printf("n=%d, 2^n-1=%d\n", n, (1L<<n) - 1);
} else { //上记范围外
BigDecimal b = new BigDecimal(2);
b = b.pow(n);
b = b.subtract(BigDecimal.ONE);
System.out.printf("n=%d, 2^n-1=%s\n", n, b.toString());
}
}
}
long t2 = System.currentTimeMillis();
System.out.printf("耗时 %d 毫秒\n", (t2-t1));
}

public static boolean isPNum(int num) {
if (num==2) return true;
else if (num<2 || num%2==0) return false;
int tmp = num, n = 0;
while (tmp>0) { //算出n
n++;
tmp >>= 1;
}
if (num==(1<<n)-1) {
return isPNum(n); //利用规律递归,判断num是否符合2的n次方减1
}

for (int i=3; i<=(1<<((n+1)/2)); i++) { //走到这里必然是奇数,所以for从3开始即可
if (num%i==0) return false;
}
return true;
}

public static boolean isPNum2(int num) {
for (int i = 2; i <= Math.sqrt(num); i++)
if (num % i == 0)
return false;
return num>1;
}
}
看了下你以前回答过的那个帖子,你说只要n是素数,2的n次方减1就是素数,这个结论恐怕有点问题,2的11次方减1就不是素数,另外,我觉得我这个程序太费时间了,我希望我能尽可能多的跑出更多的梅森素数
qybao 2020-04-14
  • 打赏
  • 举报
回复
判断2的n次方-1是不是素数,直接判断n是不是素数就可以了,推导过程看我以前回答的一个帖子
https://ask.csdn.net/questions/1060467
你要找出所有的梅森素数还是什么?

public class Sample {
public static void main(String[] args) {
long t1 = System.currentTimeMillis();
for (int n=0; n<100; n++) { //可以调整循环范围
if (isPNum(n)) {
if (n < 32) { //int范围内
System.out.printf("n=%d, 2^n-1=%d\n", n, (1<<n) - 1);
} else if (n < 64) { //long范围内
System.out.printf("n=%d, 2^n-1=%d\n", n, (1L<<n) - 1);
} else { //上记范围外
BigDecimal b = new BigDecimal(2);
b = b.pow(n);
b = b.subtract(BigDecimal.ONE);
System.out.printf("n=%d, 2^n-1=%s\n", n, b.toString());
}
}
}
long t2 = System.currentTimeMillis();
System.out.printf("耗时 %d 毫秒\n", (t2-t1));
}

public static boolean isPNum(int num) {
if (num==2) return true;
else if (num<2 || num%2==0) return false;
int tmp = num, n = 0;
while (tmp>0) { //算出n
n++;
tmp >>= 1;
}
if (num==(1<<n)-1) {
return isPNum(n); //利用规律递归,判断num是否符合2的n次方减1
}

for (int i=3; i<=(1<<((n+1)/2)); i++) { //走到这里必然是奇数,所以for从3开始即可
if (num%i==0) return false;
}
return true;
}

public static boolean isPNum2(int num) {
for (int i = 2; i <= Math.sqrt(num); i++)
if (num % i == 0)
return false;
return num>1;
}
}

62,628

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧