2016-12-12 19 views
1

Мне нужно создать программу, которая может вычислять аппроксимацию константы PI, используя многопоточность Java.Как написать программу расчета PI в Java, используя многопоточность?

Я намерен использовать серию Грегори-Лейбница для вычисления результата для PI/4, а затем умножить на 4, чтобы получить приближение PI.

enter image description here

Но у меня есть некоторое беспокойство о программе:

  1. Как я могу отделить процесс вычисления, так что я могу осуществить обработку многопоточной для программы? Потому что формула для общей суммы, я не знаю, как разбить их на части, а затем, в конце концов, я соберу их все.
  2. Я думаю о том, что программа выполнит формулу до бесконечности, поэтому пользователю необходимо будет предоставить некоторые способы настройки выполнения, чтобы определить, когда он должен остановиться и вернуть результат. Возможно ли и как я могу это сделать?

Это до сих пор самое большое, что я могу сделать.

public class PICalculate { 

    public static void main(String[] args) { 
     System.out.println(calculatePI(5000000) * 4); 
    } 

    static double calculatePI(int n) { 
     double result = 0.0; 
     if (n < 0) { 
      return 0.0; 
     } 
     for (int i = 0; i <= n; i++) { 
      result += Math.pow(-1, i)/((2 * i) + 1); 
     } 
     return result; 
    } 
} 
+3

, что ряд сходится очень медленно .... –

+0

Я думаю, вы не очень хорошо разбираются в потоках, поэтому вернитесь и прочитайте учебники и изучите некоторые примеры. – gpasch

+0

Одна из проблем с многопоточным подходом заключается в том, что для получения хорошего результата сначала нужно добавить небольшие термины из-за округления с плавающей запятой. Отметим также, что эта серия очень медленная, чтобы сходиться. – Bathsheba

ответ

0

Наиболее простой, но не самый оптимальный подход заключается в распределении элементов последовательности между потоками, которые у вас есть. То есть, если у вас есть 4 темы, нить один будет работать с п% 4 == 0 элементов, thread2 с п% 4 == 1 элементов и так далее

public static void main(String ... args) throws InterruptedException { 

    int threadCount = 4; 
    int N = 100_000; 
    PiThread[] threads = new PiThread[threadCount]; 
    for (int i = 0; i < threadCount; i++) { 
     threads[i] = new PiThread(threadCount, i, N); 
     threads[i].start(); 
    } 
    for (int i = 0; i < threadCount; i++) { 
     threads[i].join(); 
    } 
    double pi = 0; 
    for (int i = 0; i < threadCount; i++) { 
     pi += threads[i].getSum(); 
    } 
    System.out.print("PI/4 = " + pi); 

} 

static class PiThread extends Thread { 

    private final int threadCount; 
    private final int threadRemainder; 
    private final int N; 
    private double sum = 0; 

    public PiThread(int threadCount, int threadRemainder, int n) { 
     this.threadCount = threadCount; 
     this.threadRemainder = threadRemainder; 
     N = n; 
    } 


    @Override 
    public void run() { 
     for (int i = 0; i <= N; i++) { 
      if (i % threadCount == threadRemainder) { 
       sum += Math.pow(-1, i)/(2 * i + 1); 
      } 
     } 
    } 

    public double getSum() { 
     return sum; 
    } 
} 

PiThread является более эффективным, но, возможно, труднее читать , если цикл короче:

public void run() { 
    for (int i = threadRemainder; i <= N; i += threadCount) { 
     sum += Math.pow(-1, i)/(2 * i + 1); 
    } 
} 

в случае, если вы не хотите ограничивать себя с количеством элементов в последовательности и только по времени, вы можете следовать подходу ниже. Но обратите внимание, что она по-прежнему ограничен Long.MAX_VALUE, и вы должны будете использовать BigIntegers, BigDecimals или любой другой разумный подход к улучшению его

public static volatile boolean running = true; 

public static void main(String ... args) throws InterruptedException { 
    int threadCount = 4; 
    long timeoutMs = 5_000; 
    final AtomicLong counter = new AtomicLong(0); 
    PiThread[] threads = new PiThread[threadCount]; 
    for (int i = 0; i < threadCount; i++) { 
     threads[i] = new PiThread(counter); 
     threads[i].start(); 
    } 

    Thread.sleep(timeoutMs); 
    running = false; 

    for (int i = 0; i < threadCount; i++) { 
     threads[i].join(); 
    } 

    double sum = 0; 
    for (int i = 0; i < threadCount; i++) { 
     sum += threads[i].getSum(); 
    } 
    System.out.print("counter = " + counter.get()); 
    System.out.print("PI = " + 4*sum); 

} 

static class PiThread extends Thread { 

    private AtomicLong counter; 
    private double sum = 0; 

    public PiThread(AtomicLong counter) { 
     this.counter = counter; 
    } 


    @Override 
    public void run() { 
     long i; 
     while (running && isValidCounter(i = counter.getAndAdd(1))) { 
      sum += Math.pow(-1, i)/(2 * i + 1); 
     } 
    } 

    private boolean isValidCounter(long value) { 
     return value >= 0 && value < Long.MAX_VALUE; 
    } 

    public double getSum() { 
     return sum; 
    } 
} 
+0

Что ограничено Long.MAX_VALUE? Также, как работает второй подход? Каждый поток будет ждать времени, когда другой умрет, а затем продолжит? Я до сих пор не знаю, как каждый поток сохраняет свой результат, а другой поток не наступает на предыдущий расчет? –

+0

Я заметил, что во втором подходе программа не выйдет после завершения вычисления. –

+0

Long.MAX_VALUE ограничивает количество элементов в последовательности. Все потоки выполняются одновременно, сохраняя частичную сумму в соответствующей переменной. После того, как выполнение дополнительных потоков завершено или прерывается таймаутом, все частичные суммы складываются вместе. –

 Смежные вопросы

  • Нет связанных вопросов^_^