|
|
@@ -58,218 +58,200 @@ class Parallel implements Solver { |
|
|
|
|
|
|
|
class FactorWorker implements Runnable { |
|
|
|
FactorMonitor monitor; |
|
|
|
long num; |
|
|
|
int sqrt; |
|
|
|
int[] primes; |
|
|
|
int step; |
|
|
|
int offset; |
|
|
|
long num; |
|
|
|
long currentPrime; |
|
|
|
long biggestPossible; |
|
|
|
Sieve sieve; |
|
|
|
boolean ready = false; |
|
|
|
boolean done = false; |
|
|
|
boolean running; |
|
|
|
boolean done; |
|
|
|
|
|
|
|
// Offset should start at 0 |
|
|
|
synchronized public void start(FactorMonitor monitor, int step, int offset) { |
|
|
|
FactorWorker(FactorMonitor monitor, int step, int offset) { |
|
|
|
this.monitor = monitor; |
|
|
|
this.primes = monitor.primes; |
|
|
|
this.num = monitor.num; |
|
|
|
this.sqrt = (int)Math.sqrt(num); |
|
|
|
this.step = step; |
|
|
|
this.offset = offset; |
|
|
|
this.num = monitor.currentNum; |
|
|
|
this.biggestPossible = (long)Math.sqrt(num); |
|
|
|
this.sieve = monitor.sieve; |
|
|
|
notify(); |
|
|
|
|
|
|
|
this.ready = true; |
|
|
|
this.done = false; |
|
|
|
|
|
|
|
findFirstPrime(); |
|
|
|
} |
|
|
|
|
|
|
|
void findFirstPrime() { |
|
|
|
currentPrime = 3; |
|
|
|
for (int i = 0; i < offset; ++i) { |
|
|
|
currentPrime += 2; |
|
|
|
while (!monitor.isPrime(currentPrime)) |
|
|
|
currentPrime += 2; |
|
|
|
} |
|
|
|
} |
|
|
|
void go() { |
|
|
|
int start = offset + monitor.sequentialPrimes; |
|
|
|
for (int i = start; monitor.running; i += step) { |
|
|
|
if (primes[i] == 0 || primes[i] > sqrt) |
|
|
|
break; |
|
|
|
|
|
|
|
synchronized public void stop() { |
|
|
|
ready = false; |
|
|
|
done = true; |
|
|
|
notify(); |
|
|
|
} |
|
|
|
|
|
|
|
void nextPrime() { |
|
|
|
if (currentPrime > biggestPossible) |
|
|
|
return; |
|
|
|
|
|
|
|
for (int i = 0; i < step; ++i) { |
|
|
|
currentPrime += 2; |
|
|
|
while (!monitor.isPrime(currentPrime) && currentPrime <= biggestPossible) |
|
|
|
currentPrime += 2; |
|
|
|
|
|
|
|
if (currentPrime > biggestPossible) { |
|
|
|
this.ready = false; |
|
|
|
monitor.foundBiggest(); |
|
|
|
return; |
|
|
|
if (num % primes[i] == 0) { |
|
|
|
monitor.addFactor(primes[i], num); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
running = false; |
|
|
|
monitor.workerStopped(); |
|
|
|
} |
|
|
|
|
|
|
|
void findFactor() { |
|
|
|
boolean found = false; |
|
|
|
while (!found && this.ready) { |
|
|
|
if ((num % currentPrime) == 0) { |
|
|
|
found = true; |
|
|
|
if (!monitor.addFactor(currentPrime, num)) { |
|
|
|
this.num = monitor.currentNum; |
|
|
|
findFirstPrime(); |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
synchronized void start(long num) { |
|
|
|
this.num = num; |
|
|
|
this.sqrt = (int)Math.sqrt(num); |
|
|
|
running = true; |
|
|
|
notify(); |
|
|
|
} |
|
|
|
|
|
|
|
nextPrime(); |
|
|
|
} |
|
|
|
synchronized void stop() { |
|
|
|
done = true; |
|
|
|
notify(); |
|
|
|
} |
|
|
|
|
|
|
|
synchronized public void run() { |
|
|
|
while (!ready && !done) |
|
|
|
try { wait(); } catch (InterruptedException ex) {} |
|
|
|
|
|
|
|
while (!done) { |
|
|
|
while (!monitor.isDone() && this.ready) { |
|
|
|
findFactor(); |
|
|
|
} |
|
|
|
|
|
|
|
ready = false; |
|
|
|
|
|
|
|
while (!ready && !done) |
|
|
|
while (!running && !done) |
|
|
|
try { wait(); } catch (InterruptedException ex) {} |
|
|
|
|
|
|
|
if (!done) |
|
|
|
go(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
class FactorMonitor { |
|
|
|
final int sequentialPrimes = 4; |
|
|
|
|
|
|
|
Sieve sieve; |
|
|
|
long original; |
|
|
|
long currentNum; |
|
|
|
int biggestLeft; |
|
|
|
long num; |
|
|
|
int nThreads; |
|
|
|
|
|
|
|
int[] primes; |
|
|
|
boolean running; |
|
|
|
boolean done; |
|
|
|
boolean foundFactor; |
|
|
|
|
|
|
|
int workersLeft; |
|
|
|
|
|
|
|
FactorWorker[] workers; |
|
|
|
Thread[] threads; |
|
|
|
|
|
|
|
boolean done = false; |
|
|
|
ArrayList<Long> arr = new ArrayList<>(); |
|
|
|
ArrayList<Long> factors = new ArrayList<>(); |
|
|
|
|
|
|
|
FactorMonitor(Sieve sieve, long num, int nThreads) { |
|
|
|
this.sieve = sieve; |
|
|
|
this.original = num; |
|
|
|
this.currentNum = num; |
|
|
|
this.biggestLeft = nThreads; |
|
|
|
|
|
|
|
// We don't want to have to deal with the fact that 2 is a prime |
|
|
|
if (num % 2 == 0) |
|
|
|
addFactor(2, num); |
|
|
|
} |
|
|
|
this.primes = sieve.getPrimes(); |
|
|
|
this.num = num; |
|
|
|
this.nThreads = nThreads; |
|
|
|
|
|
|
|
synchronized boolean addFactor(long factor, long num) { |
|
|
|
// If the thread is working with a stale num, |
|
|
|
// just discard it and tell the thread to restart. |
|
|
|
if (num != currentNum) |
|
|
|
return false; |
|
|
|
this.done = false; |
|
|
|
|
|
|
|
while ((currentNum % factor) == 0) { |
|
|
|
currentNum /= factor; |
|
|
|
Long i = new Long(factor); |
|
|
|
arr.add(i); |
|
|
|
// We do the first few primes sequentially, as they're |
|
|
|
// very likely to be factors |
|
|
|
for (int i = 0; i < sequentialPrimes; ++i) { |
|
|
|
while (this.num % primes[i] == 0) { |
|
|
|
factors.add(new Long(primes[i])); |
|
|
|
this.num /= primes[i]; |
|
|
|
} |
|
|
|
} |
|
|
|
notify(); |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
synchronized void foundBiggest() { |
|
|
|
this.biggestLeft -= 1; |
|
|
|
if (biggestLeft == 0) { |
|
|
|
done = true; |
|
|
|
notify(); |
|
|
|
this.workers = new FactorWorker[nThreads]; |
|
|
|
this.threads = new Thread[nThreads]; |
|
|
|
for (int i = 0; i < nThreads; ++i) { |
|
|
|
FactorWorker w = new FactorWorker(this, nThreads, i); |
|
|
|
Thread t = new Thread(w); |
|
|
|
this.workers[i] = w; |
|
|
|
this.threads[i] = t; |
|
|
|
t.start(); |
|
|
|
} |
|
|
|
|
|
|
|
go(); |
|
|
|
} |
|
|
|
|
|
|
|
boolean isPrime(long num) { |
|
|
|
if (num > sieve.maxNum) |
|
|
|
return false; |
|
|
|
else |
|
|
|
return sieve.isPrime((int)num); |
|
|
|
synchronized void addFactor(int prime, long num) { |
|
|
|
foundFactor = true; |
|
|
|
if (num != this.num) |
|
|
|
return; |
|
|
|
|
|
|
|
do { |
|
|
|
this.num /= prime; |
|
|
|
factors.add(new Long(prime)); |
|
|
|
} while (this.num % prime == 0); |
|
|
|
running = false; |
|
|
|
} |
|
|
|
|
|
|
|
synchronized boolean isDone() { |
|
|
|
if (done) { |
|
|
|
return true; |
|
|
|
} else if (isPrime(currentNum)) { |
|
|
|
synchronized void workerStopped() { |
|
|
|
workersLeft -= 1; |
|
|
|
if (workersLeft != 0) |
|
|
|
return; |
|
|
|
|
|
|
|
if (foundFactor) { |
|
|
|
go(); |
|
|
|
} else { |
|
|
|
done = true; |
|
|
|
if (currentNum != 1) |
|
|
|
arr.add(new Long(currentNum)); |
|
|
|
notify(); |
|
|
|
return true; |
|
|
|
} else { |
|
|
|
return false; |
|
|
|
|
|
|
|
for (FactorWorker w: workers) |
|
|
|
w.stop(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
synchronized long[] getFactors() { |
|
|
|
while (!isDone()) |
|
|
|
while (!done) |
|
|
|
try { wait(); } catch (InterruptedException ex) {} |
|
|
|
|
|
|
|
Long curr = new Long(currentNum); |
|
|
|
if (currentNum > (long)Math.sqrt(original) && !arr.contains(curr)) |
|
|
|
arr.add(curr); |
|
|
|
if (num != 1) |
|
|
|
factors.add(new Long(num)); |
|
|
|
|
|
|
|
long[] a = new long[arr.size()]; |
|
|
|
for (int i = 0; i < a.length; ++i) { |
|
|
|
a[i] = arr.get(i); |
|
|
|
} |
|
|
|
return a; |
|
|
|
long[] arr = new long[factors.size()]; |
|
|
|
for (int i = 0; i < arr.length; ++i) |
|
|
|
arr[i] = factors.get(i); |
|
|
|
|
|
|
|
Arrays.sort(arr); |
|
|
|
return arr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
FactorWorker[] factorWorkers = null; |
|
|
|
Thread[] factorThreadPool = null; |
|
|
|
synchronized void go() { |
|
|
|
running = true; |
|
|
|
foundFactor = false; |
|
|
|
workersLeft = nThreads; |
|
|
|
for (FactorWorker w: workers) |
|
|
|
w.start(num); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public long[] factor(Sieve sieve, long num) { |
|
|
|
int nThreads = Runtime.getRuntime().availableProcessors(); |
|
|
|
nThreads = Math.min(nThreads, 8); |
|
|
|
|
|
|
|
if (num <= sieve.maxNum && sieve.isPrime((int)num)) |
|
|
|
return new long[] { num }; |
|
|
|
FactorMonitor monitor = new FactorMonitor(sieve, num, nThreads); |
|
|
|
return monitor.getFactors(); |
|
|
|
|
|
|
|
// Initiate thread pool |
|
|
|
if (factorThreadPool == null) { |
|
|
|
factorThreadPool = new Thread[nThreads]; |
|
|
|
factorWorkers = new FactorWorker[nThreads]; |
|
|
|
for (int i = 0; i < nThreads; ++i) { |
|
|
|
FactorWorker w = new FactorWorker(); |
|
|
|
factorWorkers[i] = w; |
|
|
|
factorThreadPool[i] = new Thread(w); |
|
|
|
factorThreadPool[i].start(); |
|
|
|
} |
|
|
|
} |
|
|
|
/* |
|
|
|
int[] primes = sieve.getPrimes(); |
|
|
|
|
|
|
|
FactorMonitor monitor = new FactorMonitor(sieve, num, nThreads); |
|
|
|
ArrayList<Long> factors = new ArrayList<>(); |
|
|
|
int sqrt = (int)Math.sqrt(num); |
|
|
|
for (int i = 0; i < primes.length; ++i) { |
|
|
|
int p = primes[i]; |
|
|
|
if (p == 0) |
|
|
|
break; |
|
|
|
|
|
|
|
// Start workers |
|
|
|
for (int i = 0; i < nThreads; ++i) { |
|
|
|
FactorWorker w = factorWorkers[i]; |
|
|
|
w.start(monitor, nThreads, i); |
|
|
|
if (p > sqrt) |
|
|
|
break; |
|
|
|
|
|
|
|
while (num % p == 0) { |
|
|
|
factors.add(new Long(p)); |
|
|
|
num /= p; |
|
|
|
sqrt = (int)Math.sqrt(num); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
long[] arr = monitor.getFactors(); |
|
|
|
Arrays.sort(arr); |
|
|
|
if (num != 1) |
|
|
|
factors.add(num); |
|
|
|
|
|
|
|
long[] arr = new long[factors.size()]; |
|
|
|
for (int i = 0; i < arr.length; ++i) |
|
|
|
arr[i] = factors.get(i); |
|
|
|
return arr; |
|
|
|
*/ |
|
|
|
} |
|
|
|
|
|
|
|
public void stopThreads() { |
|
|
|
if (factorWorkers == null) |
|
|
|
return; |
|
|
|
|
|
|
|
for (FactorWorker w: factorWorkers) { |
|
|
|
w.stop(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |