我使用程序从数学运行Collatz猜想(http://en.wikipedia.org/wiki/Collatz_conjecture)。我实现了一个运行猜想算法的类(并返回输出)和一个创建固定线程池(使用我的处理器数量:8)的类,并接受Callable
个调用猜想算法。
我为1之间的所有数字(输入类型必须是正整数)和400,000之间的数字创建了HashSet<Callable>
。这似乎永远挂起,但较低的数字很好,这很奇怪。更奇怪的是,运行它似乎需要更长的时间来处理这些调用,而不是需要一个线程来处理相同数量的信息;它也大大增加了记忆力。
例如,在我的计算机上,程序花费不到一秒的时间来执行算法(只需一次迭代)400,000(最终值),所有较低的值花费较少的时间来计算(可能除了素数之外) ,花费更长的时间)我运行的是带有8GB内存的Windows 8.1和带有2.2Ghz的8个逻辑处理器。
代码:
private static void initThreads() throws InterruptedException {
//Files.createDirectories(SEQUENCER_FOLDER_PATH);
//Files.createFile(SEQUENCER_FILE_PATH);
ExecutorService service = Executors.newFixedThreadPool(8, new ThreadFactory() {
private BigInteger count = BigInteger.ZERO;
@Override
public Thread newThread(Runnable r) {
count = count.add(BigInteger.ONE);
return new Thread(r, "Collatz Sequencer Thread: " + count);
}
});
int finalNumber = 400_000;
final HashSet<Callable<Void>> tasks = new HashSet<>(finalNumber);
for (long l = 1; l <= finalNumber; l++) {
final BigInteger number = BigInteger.valueOf(l);
tasks.add(() -> {
CollatzSequencer sequencer = new CollatzSequencer(new BigInteger(number.toString()));
synchronized (dataSet) {
dataSet.put(number, sequencer.init());
}
return null;
});
}
service.invokeAll(tasks);
Thread dataThread = new Thread(() -> {
while (true) {
synchronized (dataSet) {
if (dataSet.size() == finalNumber) {
System.err.println("Values: \n");
for (CollatzSequencer.FinalSequencerReport data : dataSet.values()) {
System.err.println("Entry: " + data.getInitialValue() + ", " + data.getIterations());
}
System.exit(0);
}
}
}
}, "Collatz Conjecture Data Set Thread");
dataThread.start();
}
Collatz猜想算法:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.collatzsequencer.core;
import java.math.BigInteger;
/**
* A sequencer used for computing the collatz sequence.
*
* @author Sarah Szabo
* @version 1.0
*/
public class CollatzSequencer {
private final BigInteger initialValue;
public CollatzSequencer(BigInteger currentValue) {
if (currentValue == null) {
throw new NullPointerException("Value passed can't be null");
} else if (currentValue.compareTo(new BigInteger("1")) < 0) {
throw new NumberFormatException("The value passed to the constructor must be a natural number.");
}
this.initialValue = currentValue;
}
public FinalSequencerReport init() {
return new FinalSequencerReport(performOperation(new SequencerReport(this.initialValue)), this.initialValue);
}
private SequencerReport performOperation(SequencerReport report) {
if (report.getResult().equals(new BigInteger("1"))) {
return new SequencerReport(report.getResult(), report.getIterations(), report.getSequence().length() > 1
? report.getSequence().substring(0, report.getSequence().length() - 3) : "The sequence starts and ends at 1 <Nothing Done>");
} else if (report.getResult().mod(new BigInteger("2")).equals(new BigInteger("0"))) {
BigInteger value = report.getResult().divide(new BigInteger("2"));
return performOperation(new SequencerReport(value, report.getIterations().add(new BigInteger("1")),
report.getSequence() + " " + report.getResult() + "/2 -> " + value + " ->"));
} else {
BigInteger value = report.getResult().multiply(new BigInteger("3")).add(new BigInteger("1"));
return performOperation(new SequencerReport(value, report.getIterations()
.add(new BigInteger("1")), report.getSequence() + report.getResult() + " * 3 + 1 ->" + value + " ->"));
}
}
public static final class FinalSequencerReport extends SequencerReport {
private final BigInteger initialValue;
private final String finalFormattedString;
public FinalSequencerReport(SequencerReport finalReport, BigInteger initialValue) {
super(finalReport.getResult(), finalReport.getIterations(), finalReport.getSequence());
this.initialValue = initialValue;
this.finalFormattedString = "Initial Value: "
+ getInitialValue() + "\nFinal Value: " + getResult() + "\nIterations: "
+ getIterations() + "\nAlgebraic Sequence:\n" + getSequence();
}
public String getFinalFormattedString() {
return finalFormattedString;
}
public BigInteger getInitialValue() {
return initialValue;
}
}
public static class SequencerReport {
private final BigInteger result, iterations;
private final String sequence;
public SequencerReport(BigInteger result) {
this(result, new BigInteger("0"), "");
}
public SequencerReport(BigInteger result, BigInteger iterations, String sequence) {
this.result = result;
this.iterations = iterations;
this.sequence = sequence;
}
public BigInteger getResult() {
return this.result;
}
public BigInteger getIterations() {
return this.iterations;
}
public String getSequence() {
return this.sequence;
}
}
}
答案 0 :(得分:1)
正如你所说,你的代码有效;问题可能只是表现。我会尝试一些事情:
long
代替BigInteger
。 BigInteger
非常慢。mod 2
(或% 2
),使用 & 1
。二进制AND将有效地获得相同的结果并且速度更快。String
操纵。覆盖sequencerReport.toString()
,并在您打印数据时让所有toString
电话完成。new ThreadFactory()
。使用Guava's ThreadFactoryBuilder。
new Thread()
,这意味着不要这样做。dataThread
添加等待/通知机制,而不是忙循环。完成工作后致电dataSet.notify()
,dataSet.wait()
正文内部dataThread
。