I'm using a program to run the Collatz Conjecture (http://en.wikipedia.org/wiki/Collatz_conjecture) from mathematics. I've implemented a class that runs the conjecture algorithm (and gives you back the output) and one that creates a fixed thread pool (with my number of processors: 8) and accepts Callable
s which are calls for the conjecture algorithm.
I created a HashSet<Callable>
for all the numbers between 1 (the input type must be a positive integer) and 400,000. This hangs (seemingly) forever, but lower numbers work out just fine, which is strange. Stranger yet, running it appears to take longer to process these calls than it takes a single thread to process the same amount of information; it also bloats the memory significantly.
For instance, on my computer, the program takes less than a second to perform the algorithm (just one iteration) with 400,000 (the final value) and all the lower values take less time to compute (maybe with the exception of primes, which take longer) I'm running Windows 8.1 with 8GB ram, and 8 logical processors at 2.2Ghz.
Code:
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 Conjecture Algorithm:
/*
* 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;
}
}
}