123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- import java.util.ArrayList;
- import java.util.Arrays;
-
- class Parallel implements Solver {
- class SolverWorker implements Runnable {
- Sieve sieve;
- int step;
- int offset;
-
- SolverWorker(Sieve mainSieve, int step, int offset) {
- byte[] arr = new byte[mainSieve.arr.length];
- System.arraycopy(mainSieve.arr, 0, arr, 0, arr.length);
-
- this.sieve = new Sieve(mainSieve.maxNum, arr);
- this.sieve.smallPrimesGenerated = true;
-
- this.step = step;
- this.offset = offset;
- }
-
- public void run() {
- sieve.generatePrimes(step, offset);
- }
- }
-
- public void solve(Sieve sieve) {
- // Generate primes less than sqrt(n)
- sieve.generateSmallPrimes();
-
- int nThreads = Runtime.getRuntime().availableProcessors();
- nThreads = Math.min(nThreads, 8);
-
- Thread[] threads = new Thread[nThreads];
- SolverWorker[] workers = new SolverWorker[nThreads];
-
- // Start threads
- for (int i = 0; i < nThreads; ++i) {
- SolverWorker w = new SolverWorker(sieve, nThreads, (i * 2) + 1);
- workers[i] = w;
-
- Thread t = new Thread(w);
- threads[i] = t;
- t.start();
- }
-
- // Wait for threads
- for (Thread t: threads) {
- try { t.join(); } catch (InterruptedException ex) {}
- }
-
- // Merge
- for (int i = 0; i < sieve.arr.length; ++i) {
- for (SolverWorker w: workers) {
- sieve.arr[i] = (byte)(sieve.arr[i] | w.sieve.arr[i]);
- }
- }
- }
-
- class FactorWorker implements Runnable {
- FactorMonitor monitor;
- long num;
- int sqrt;
- int[] primes;
- int step;
- int offset;
- boolean running;
- boolean done;
-
- 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.done = false;
- }
-
- void go() {
- int start = offset + monitor.sequentialPrimes;
- for (int i = start; monitor.running; i += step) {
- if (primes[i] == 0 || primes[i] > sqrt)
- break;
-
- if (num % primes[i] == 0) {
- monitor.addFactor(primes[i], num);
- break;
- }
- }
-
- running = false;
- monitor.workerStopped();
- }
-
- synchronized void start(long num) {
- this.num = num;
- this.sqrt = (int)Math.sqrt(num);
- running = true;
- notify();
- }
-
- synchronized void stop() {
- done = true;
- notify();
- }
-
- synchronized public void run() {
- while (!done) {
- while (!running && !done)
- try { wait(); } catch (InterruptedException ex) {}
-
- if (!done)
- go();
- }
- }
- }
-
- class FactorMonitor {
- final int sequentialPrimes = 4;
-
- Sieve sieve;
- long num;
- int nThreads;
-
- int[] primes;
- boolean running;
- boolean done;
- boolean foundFactor;
-
- int workersLeft;
-
- FactorWorker[] workers;
- Thread[] threads;
-
- ArrayList<Long> factors = new ArrayList<>();
-
- FactorMonitor(Sieve sieve, long num, int nThreads) {
- this.primes = sieve.getPrimes();
- this.num = num;
- this.nThreads = nThreads;
-
- this.done = false;
-
- // 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];
- }
- }
-
- 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();
- }
-
- 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 void workerStopped() {
- workersLeft -= 1;
- if (workersLeft != 0)
- return;
-
- if (foundFactor) {
- go();
- } else {
- done = true;
- notify();
-
- for (FactorWorker w: workers)
- w.stop();
- }
- }
-
- synchronized long[] getFactors() {
- while (!done)
- try { wait(); } catch (InterruptedException ex) {}
-
- if (num != 1)
- factors.add(new Long(num));
-
- long[] arr = new long[factors.size()];
- for (int i = 0; i < arr.length; ++i)
- arr[i] = factors.get(i);
-
- Arrays.sort(arr);
- return arr;
- }
-
- 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);
-
- FactorMonitor monitor = new FactorMonitor(sieve, num, nThreads);
- return monitor.getFactors();
- }
-
- public void stopThreads() {
- }
- }
|