Вычисления приближенное значение числа Пи с помощью метода Монте-Карло в Java с потоками


У меня это небольшая программа, которая пытается вычислить приближенное значение \$\Пи\$:

package net.coderodde.fun;

import java.awt.geom.Point2D;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * This class computes an approximate value of Pi. 
 * 
 * @author Rodion "rodde" Efremov
 * @version 1.6 (Feb 23, 2018)
 */
public class MonteCarloPiComputer {

    /**
     * The default radius of the simulated circle.
     */
    private static final double DEFAULT_RADIUS = 0.5;

    /**
     * The random number generator.
     */
    private final Random random;

    public MonteCarloPiComputer(Random random) {
        this.random = 
                Objects.requireNonNull(
                        random, 
                        "The input random number generator is null.");
    }

    public MonteCarloPiComputer() {
        this(new Random());
    }

    /**
     * Computes an approximate value of Pi via a Monte Carlo method. The method
     * creates {@code samples} random points, computes the percentage of all 
     * points within the radius from the center of the simulated square and 
     * multiplies it by {@code 4.0}.
     * 
     * @param samples the number of points to create.
     * @param radius  the radius of the simulated circle.
     * @return an approximate value of Pi.
     */
    public double computeApproximateValueOfPi(int samples, double radius) {
        Point2D.Double center = new Point2D.Double(radius, radius);
        double squareSideLength = 2.0 * radius;
        long numberOfPointsWithinCircle = 
            IntStream.range(0, samples)
                     .mapToObj(
                             (i) -> { 
                                 return new Point2D.Double(
                                         squareSideLength * random.nextDouble(),
                                         squareSideLength * random.nextDouble()); 
                             })
                     .filter((point) -> { 
                         return point.distance(center) < radius; 
                     }).count();

        return (4.0 * numberOfPointsWithinCircle) / samples;
    }

    /**
     * Computes an approximate value of Pi via a Monte Carlo method with default
     * radius.
     * 
     * @param samples the number of points to create.
     * @return an approximate value of Pi.
     */
    public double computeApproximateValueOfPi(int samples) {
        return computeApproximateValueOfPi(samples, DEFAULT_RADIUS);
    }

    public static void main(String[] args) {
        MonteCarloPiComputer computer = new MonteCarloPiComputer();

        for (int samples = 100_000; samples <= 1_000_000; samples += 100_000) {
            double approximation = 
                    computer.computeApproximateValueOfPi(samples);
            double percentage = approximation / Math.PI;
            System.out.print(String.format("%7d: ", samples));
            System.out.print(String.format("%10f", approximation));
            System.out.println(
                    String.format(
                            ", percentage from exact Pi: %10f", 
                            (100.0 * percentage)));
        }
    }
}

Критика запросу

Хотелось бы услышать любые комментарии и предложения по улучшению.



274
4
задан 23 февраля 2018 в 07:02 Источник Поделиться
Комментарии
1 ответ

У вас есть немного лишнего importС. Я тоже думаю, что можно переименовать computeApproximateValueOfPi() для approximatePi() без потери четкости.

Моделирование осложняется тем, что круг с центром в регулируемый момент (radius, radius). Вы могли бы также просто использовать единичную окружность с центром в начальной точке, и генерировать точки в квадрат с х в диапазоне [0, 1) и г в интервале [0, 1). Расчет является математически эквивалентным, с меньшим сдвигом и масштабированием.

Кроме того, нет необходимости, чтобы инстанцировать Point2D для каждой полученной точки. Вы можете использовать .distance(<em>x</em>, <em>y</em>). Еще лучше, избежать вычисления квадратного корня с помощью .distanceSq(<em>x</em>, <em>y</em>).

Режим выхода в main() можно было бы улучшить. Ваш percentage переменная не хранит процент, как предполагает его название; в 100× происходит в форматирование вместо. Разделение форматирование на несколько System.out.print() вызывает поражения цели String.format(). Я хотела объединить их все в один System.out.format() вызова. Наконец, "процент от" формулировка подразумевает, что вы вычисляете разницу; расчет на то, что вы действительно выполнили то, что я бы назвал "процент".

import java.awt.geom.Point2D;
import java.util.Objects;
import java.util.Random;
import java.util.stream.IntStream;

public class MonteCarloPiComputer {
/**
* The random number generator.
*/
private final Random random;

public MonteCarloPiComputer(Random random) {
this.random = Objects.requireNonNull(
random,
"The input random number generator is null."
);
}

public MonteCarloPiComputer() {
this(new Random());
}

/**
* Computes an approximate value of Pi via a Monte Carlo method. The method
* creates {@code samples} random points in the upper-right quadrant,
* computes the fraction of all points within the radius from the origin
* and multiplies it by {@code 4.0}.
*
* @param samples the number of points to create.
* @return an approximate value of Pi.
*/
public double approximatePi(int samples) {
Random r = this.random;
Point2D.Double origin = new Point2D.Double();
long pointsWithinUnitArc = IntStream.range(0, samples)
.filter(i -> origin.distanceSq(r.nextDouble(), r.nextDouble()) < 1)
.count();
return (4.0 * pointsWithinUnitArc) / samples;
}

public static void main(String[] args) {
MonteCarloPiComputer computer = new MonteCarloPiComputer();

for (int samples = 100_000; samples <= 1_000_000; samples += 100_000) {
double approximation = computer.approximatePi(samples);
double pctDiff = 100 * (approximation - Math.PI) / Math.PI;
System.out.format("%7d: %10f, deviation from exact Pi: %+10f%%%n",
samples,
approximation,
pctDiff
);
}
}
}

2
ответ дан 23 февраля 2018 в 08:02 Источник Поделиться