gpt4 book ai didi

java - 如何并发素数分解?

转载 作者:搜寻专家 更新时间:2023-10-31 19:49:27 26 4
gpt4 key购买 nike

以下代码片段计算给定数字的质因数:

public static LinkedList<Long> getPrimeFactors(Long number) {
LinkedList<Long> primeFactors = new LinkedList<Long>();

for (Long factor = Long.valueOf(2); factor <= number / factor; factor++) {
if (number % factor == 0) {
primeFactors.add(factor);
while (number % factor == 0) {
number /= factor;
}
}
}

if (number > 1) {
primeFactors.add(number);
}

return primeFactors;
}

计算 9223372036854775783 的质因数需要 140937 毫秒(它是最后一个小于 Long.MAX_VALUE 的质数)。有什么方法可以通过并发实现这种因式分解,即使用 ExecutorService

编辑:

public static void getPrimeFactors(Long number) {
LinkedList<Long> primeFactors = new LinkedList<Long>();

if (number % 2 == 0) {
primeFactors.add(2L);

while (number % 2 == 0) {
number /= 2;
}
}

long limit = (long) Math.sqrt(number) + 1;

ExecutorService service = Executors.newFixedThreadPool(2);
LinkedList<Future<LinkedList<Long>>> futures = new LinkedList<Future<LinkedList<Long>>>();
futures.add(service.submit(new PrimeFactor(3, limit / 2, number)));
futures.add(service.submit(new PrimeFactor(1 + limit / 2, limit, number)));

for (Future<LinkedList<Long>> future : futures) {
try {
primeFactors.addAll(future.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
service.shutdown();

if(number>1) {
primeFactors.add(number);
}

System.out.println(primeFactors);
}

private static class PrimeFactor implements Callable<LinkedList<Long>> {
private long lowerLimit;
private long upperLimit;
private Long number;

public PrimeFactor(long lowerLimit, long upperLimit, Long number) {
this.lowerLimit = lowerLimit;
this.upperLimit = upperLimit;
this.number = number;
}

public LinkedList<Long> call() throws Exception {
LinkedList<Long> primeFactors = new LinkedList<Long>();
for (long i = lowerLimit; i < upperLimit; i += 2) {
if (number % i == 0) {
primeFactors.add(i);
while (number % 2 == 0) {
number /= i;
}
}
}
return primeFactors;
}

}

第二次编辑:

public static LinkedList<Long> getPrimeFactorsByFastGeneralMethod(long number) {
LinkedList<Long> primeFactors = new LinkedList<Long>();

if (number % 2 == 0) {
primeFactors.add(2L);

while (number % 2 == 0) {
number /= 2;
}
}

long limit = (long) Math.sqrt(number);

for (long factor = 3; factor <= limit; factor += 2) {
if (number % factor == 0) {
primeFactors.add(factor);
while (number % factor == 0) {
number /= factor;
}
}
}

if (number > 1) {
primeFactors.add(number);
}

return primeFactors;
}

现在的代码片段:

    LinkedList<Long> primeFactors = Factorization.getPrimeFactorsByConcurrentGeneralMethod(600851475143L);
System.out.println("Result: " + primeFactors.get(primeFactors.size() - 1));

primeFactors = Factorization.getPrimeFactorsByFastGeneralMethod(600851475143L);
System.out.println("Result: " + primeFactors.get(primeFactors.size() - 1));

正在给出输出:

Result: 600851475143
Result: 6857

注意:类名是Factorization,我把方法名getPrimeFactors改成了getPrimeFactorsByConcurrentGeneralMethod

最佳答案

呃,在您开始考虑并发实现之前,我建议稍微优化一下算法。除了 2 之外,每个素数都是奇数,所以将 2 作为一个特例,然后从循环 3 开始并将因子增加 2。然后不是计算每个循环结束的数字/因子(我认为这也使得 JIT 的优化更加困难) 只需计算 Sqrt(N) 一次——毕竟我们知道每个数字只能有一个质因数 > sqrt(N) ;)

如果您这样做了,我会更改您的方法签名,这样您就不会总是从 3 开始一直工作到 Sqrt(N),而是为其指定开始和结束范围。最简单的解决方案是将范围从 3-Sqrt(N) 分成 K 个部分,其中 K 是可用内核的数量(因为这并不是真正平衡的,使用较小的部分可能会给您带来更好的负载平衡)并将其放入刽子手服务。然后您只需收集所有结果并从所有较小的列表中创建一个列表。

请注意,这种简单的方法对 BigIntegers 做了更多的工作,因为您总是计算起始数字的值,并且每个除法算法的复杂性在某处取决于位大小 - 如果您使用较小的作业大小和同步,您也可以解决这个问题在这些之间。

PS:请注意,您的拆分范围算法仍然必须正确处理情况 2 和 sqrt(n)。

PPS:我希望您知道这个问题存在于 NP 中,您这样做只是为了了解一点并发性。

关于java - 如何并发素数分解?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6484156/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com