Java 如何使用附加线程以更快的方式确定一个数字是否为素数?
我有一个素数类的程序。它显示x是否为素数。x是程序中正在分析的数字 程序需要多长时间才能知道答案还有时间。x太大了,需要9秒钟才能知道答案。如何使用更多线程使程序运行得更快?在这种情况下,我很难理解如何实现线程Java 如何使用附加线程以更快的方式确定一个数字是否为素数?,java,multithreading,primes,Java,Multithreading,Primes,我有一个素数类的程序。它显示x是否为素数。x是程序中正在分析的数字 程序需要多长时间才能知道答案还有时间。x太大了,需要9秒钟才能知道答案。如何使用更多线程使程序运行得更快?在这种情况下,我很难理解如何实现线程 public class PrimeNumbers { private static int x = 2147483647; public static boolean prime= true; public static void main(String[]
public class PrimeNumbers {
private static int x = 2147483647;
public static boolean prime= true;
public static void main(String[]args){
long start, end, elapsetime;
start= System.currentTimeMillis();
for(int y=2; y<x; y++){
if(x % y == 0){
prime=false;
System.out.println(y);
break;
}
}
end = System.currentTimeMillis();
elapsetime = end - start;
System.out.println("Prime: " + prime);
System.out.println(elapsetime+ " mill sec " + (elapsetime / 1000
+ " seconds."));
}
}
我将不考虑您是否有最有效的方法,而将重点放在如何使用更多线程加快当前代码的速度上 您当前遍历2->x中的所有数字,并执行一个简单的测试。提高性能的一种方法可能是将此任务分成Z个块,并启动Z个线程并行执行测试 例如,如果你有两个线程,你会让一个线程检查2->x/2,另一个检查x/2+1->x。如果全局且可能是易失性的标志设置为true,则每个线程都应中断其测试,这将表明另一个线程已对素数进行了反驳。素数测试效率非常低,在每个小于x的数字上循环。你如何改进它?这个 一个好的算法是AKS测试,或埃拉托斯烯筛。下面的代码实现了wiki文章中的一个算法,它比您发布的测试更有效
public static boolean isPrime(long n) {
// http://en.wikipedia.org/wiki/Primality test
if (n <= 3) return n > 1;
if (n % 2 == 0 || n % 3 == 0) return false;
for (int i = 5; i*i <=n; i+=6) {
if (n % i == 0 || n % (i+2) == 0) return false;
}
return true;
}
}
如果你对更好的算法感兴趣,Munyari已经提出了一个 忽略下面的示例可以帮助您如何使算法并行执行,即使它是一个愚蠢的算法 我们需要一个实现类似于Runnable的可调用接口的类。它应该得到作业的一部分并进行计算
public class PrimeChecker implements Callable<Boolean> {
private final long numberToCheck;
private final long start;
private final long end;
public PrimeChecker(long numberToCheck, long start, long end) {
this.numberToCheck = numberToCheck;
this.start = start;
if (end >= numberToCheck) {
this.end = numberToCheck - 1;
}else{
this.end = end;
}
System.out.println("A PrimeChecker with start " + start + " and end " + end + " values to check number "
+ numberToCheck);
}
@Override
public Boolean call() throws Exception {
boolean prime = true;
long current = start;
if (current != 2 && (current % 2 == 0)) {
current = current + 1;
}
for (; current < end; current = current + 2) {
if (numberToCheck % current == 0) {
prime = false;
System.out.println("The number " + numberToCheck + " is divisable with " + current);
return prime;
}
}
return prime;
}
}
您可以尝试使用不同数量的线程查看numberOfThreads变量以查看差异
我希望这是一个有用的例子,让你更好地理解多线程。小心:它只是整个线程主题的一小部分如果您不需要自己实现基本检查,我建议使用API。您可以根据自己的需要控制确定性。在本例中为:1-1/2100 编辑 以下是建议示例的优化版本
public class PrimeNumbers {
private static int x = 2147483647;
public static boolean prime= true;
public static void main(String[]args){
long start, end, elapsetime;
int divisor = 1;
start= System.currentTimeMillis();
if (x % 2 == 0) {
prime = false;
divisor = 2;
} else {
// - you can use an increment of two
// because you don't need to check
// for a divisor which is a multiple
// of two
// - you don't need to check for any divisor
// which is greater than x/2
for(int y=3; y < x/2; y += 2){
if(x % y == 0){
prime=false;
divisor = y;
break;
}
}
}
end = System.currentTimeMillis();
System.out.println("Prime: " + prime);
if (!prime) {
System.out.println("divisible by: " + divisor);
}
elapsetime = end - start;
System.out.println(elapsetime+ " mill sec " + (elapsetime / 1000
+ " seconds."));
}
}
您可以做许多改进,使其运行得更快,但这些改进不包括多线程。您可能希望得到更好的算法。@Kon为什么?多线程也有帮助。@talex高效多线程确定性素性测试非常复杂,虽然这里有很多非常简单的算法可以改进,但是一个简单的语句可以提高渐进复杂性,这里应该使用什么算法呢?这只是另一个建议,当标志变为true时,你可以杀死所有其他线程,只说不是质数。您不需要等到整个处理完成@Stackflow这就是我所说的每个线程都应该从测试中中断,如果一个全局线程。。。标志被设置为true。@user3802633为什么不根据我的描述自己做呢?有很多资源介绍如何执行多线程。如果你被卡住了,请再发一个问题。这不是AKS的素性测试。测试显示的是一个不错的简单的试算法,适合小数字,可能对原始问题也有好处。关于其他建议,AKS是一种糟糕的方法,实际上它非常慢,SoE用于生成素数,而不是确定单个输入的素数。如果您希望在更大的输入方面比试用版有更好的性能,我建议BPSW或M-R测试对于64位数字都是确定性的。谢谢您的回答。但我真的需要使用线程。不可能吗你说的真线是什么意思?解决方案实际上使用多线程。我不能使用flag或turn来加快进程吗?Hi@user3802633,如果可以存储到int变量中的素数满足您的需要,那么您可以优化代码,例如,如我的第二个代码示例所示。其他优化仍有可能。
public static void main(String[] args) {
BigInteger mersenne = new BigInteger("2").pow(521).add(BigInteger.ONE.negate());
System.out.println("digits of the number: " + mersenne.toString().length());
long start = System.currentTimeMillis();
final int certainty = 100;
boolean isPrime = mersenne.isProbablePrime(certainty);
System.out.println("elapsed millis: " + (System.currentTimeMillis() - start));
System.out.println("isPrime : " + isPrime);
}
public class PrimeNumbers {
private static int x = 2147483647;
public static boolean prime= true;
public static void main(String[]args){
long start, end, elapsetime;
int divisor = 1;
start= System.currentTimeMillis();
if (x % 2 == 0) {
prime = false;
divisor = 2;
} else {
// - you can use an increment of two
// because you don't need to check
// for a divisor which is a multiple
// of two
// - you don't need to check for any divisor
// which is greater than x/2
for(int y=3; y < x/2; y += 2){
if(x % y == 0){
prime=false;
divisor = y;
break;
}
}
}
end = System.currentTimeMillis();
System.out.println("Prime: " + prime);
if (!prime) {
System.out.println("divisible by: " + divisor);
}
elapsetime = end - start;
System.out.println(elapsetime+ " mill sec " + (elapsetime / 1000
+ " seconds."));
}
}