高分悬赏:Java语言如何编写程序判断2的n次方-1是不是质数

从键盘输入n,计算2的n次方-1是不是质数
如果是,输出yes,如果不是,输出no
比如输入:859433
输出yes

2的n次方就是1<<n(1左移n位的二进制数),2的n次方减1的二进制位都是1,从中受到启发,貌似发现了一个规律
如果该二进制数的1的串刚好被分成相同长度的2个1以上的子串的组合,则该数不是质数,否则,该数是质数(即二进制数的1的串不能分成相同长度的2个1以上的子串的组合)
比如
2的2次方-1=3的二进制11(有2个1的串),不能分成2个1以上的子串的组合,所以是质数
2的3次方-1=7的二进制111(有3个1的串),不能分成2个1以上的子串的组合,所以是质数
2的4次方-1=15的二进制1111(有4个1的串),能分成2个1以上的子串的组合(即1111可由2组11组合),所以不是质数
2的5次方-1=31的二进制11111(有5个1的串),不能分成2个1以上的子串的组合,所以是质数
2的6次方-1=63的二进制111111(有6个1的串),能分成2个1以上的子串的组合(即111111可由2组111,3组11组合)
2的7次方-1=127的二进制1111111(有7个1的串),不能分成2个1以上的子串的组合,所以是质数
2的8次方-1=255的二进制11111111(有8个1的串),能分成2个1以上的子串的组合(即11111111可由2组1111,4组11组合)
2的9次方-1=511的二进制111111111(有9个1的串),能分成2个1以上的子串的组合(即111111111可由3组111组合)
2的10次方-1=1023的二进制1111111111(有10个1的串),能分成2个1以上的子串的组合(即1111111111可由5组11组合)
等等
所以变相的改成判断二进制数有几个1组成即可,即质数个1,也就是n是质数的时候,2的n次方-1也是质数,结果发现和LS说的规律一样
剩下还有什么规律还有待挖掘,不过上述的规律可以递归利用,或许在一定程度上可以优化一下

public class Sample {
    public static void main(String[] args) {
        //Scanner sc = new Scanner(System.in);
        //int num = sc.nextInt();
        int num = 859433;
        //int num = (1<<31)-1;
        long t1 = System.currentTimeMillis();
        boolean b = isPNum(num);
        long t2 = System.currentTimeMillis();
        System.out.println(t2-t1 + "=" + b);
        t1 = System.currentTimeMillis();
        b = isPNum2(num);
        t2 = System.currentTimeMillis();
        System.out.println(t2-t1 + "=" + b);
    } 

    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;
    }
}

以后有时间再研究一下质数还有什么规律(比如从分解成2n次方之和的角度考虑)

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);

System.out.print("请输入一个整数:");

BigInteger num = sc.nextBigInteger();
while(true) {
BigInteger result=BigInteger.valueOf(1);
for(BigInteger j=BigInteger.valueOf(2);j.compareTo(num)<=0;j=j.add(BigInteger.valueOf(1))) {
result=result.multiply(BigInteger.valueOf(2));
}
result=result.multiply(num);
result=result.subtract(BigInteger.valueOf(1));
for(BigInteger j=BigInteger.valueOf(2);j.compareTo(result)<=0;j=j.add(BigInteger.valueOf(1))) {
if(result.divide(j).equals(0)) {
System.out.println("no");
break;
}
if(result.subtract(BigInteger.valueOf(1)).compareTo(j) == 0) {
System.out.println("yes");
}

        }
        System.out.println(result);
        System.out.print("请输入一个整数:");
        num =  sc.nextBigInteger();
    }

}
不是我的程序不行,是你输入的数太大了,我输入24就有点慢了,输入8884根本就计算不出来

package com.test;

import java.util.Scanner;

public class Test3 {

public static void main(String[] args) {
    // TODO Auto-generated method stub

    System.out.println("请输入n值:");
    Scanner input = new Scanner(System.in);
    String str = input.next();
    System.out.println("输入的值是:"+str);
    System.out.println("是否是质数? 答案是:"+match2(Integer.valueOf(str)));
}

/**
 * 判断是否是质数
 * 
 * @param i
 * @return
 */
private static boolean match2(int n) {
            Double d = Math.pow(2, n);
    n = d.intValue()-1;
    for (int i = 2; Math.sqrt(n) >= i; i++) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

}
//控制台
请输入n值:
15
输入的值是:15
是否是质数? 答案是:false

想要高效就用欧拉筛法 O(nloglogn)可以将数据提到1e7左右。

用C++写了一个
如果n是质数,那么(2^n)-1必定是质数

#include <iostream>
using namespace std;
bool isPrim(const int& num) {
    for (int i = 2; i <= sqrt(num); i++)
        if (num % i == 0)
            return false;
    return num>1;
}
int main() {
    int n;
    cin >> n;
    cout << (isPrim(n) ? "yes" : "no") << endl;
    return 0;
}