/
onequ1z
/
JavaCoursePaperTulSU
Обзор
Документация
Войти
/
onequ1z
/
JavaCoursePaperTulSU
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/main/java/ru/dmitry/montecarlo/service/MonteCarlo.java
164 строки
7 KB
tayno
Добавлено AvgTime для итоговой таблицы
08 дек 2025, 13:07
08 дек 2025, 13:07
ffd7c03
Код
Авторство
О чём код?
package ru.dmitry.montecarlo.service; import ru.dmitry.montecarlo.model.Figure; import ru.dmitry.montecarlo.model.MonteCarloResult; import ru.dmitry.montecarlo.model.Point; import ru.dmitry.montecarlo.model.Rectangle; import ru.dmitry.montecarlo.util.Stopwatch; import java.util.Random; /** * Сервис для оценки площади геометрических фигур методом Монте-Карло. * Генерирует случайные точки внутри ограничивающего прямоугольника * и подсчитывает количество попаданий в фигуру. * <p> * Реализует однопоточную версию алгоритма. */ public class MonteCarlo implements MonteCarloEstimator { private final Profiler profiler; /** * Создаёт экземпляр MonteCarlo без профилирования. */ public MonteCarlo() { this(new Profiler(false)); } /** * Создаёт экземпляр MonteCarlo с заданным профилировщиком. * * @param profiler профилировщик для измерения производительности (может быть null) */ public MonteCarlo(Profiler profiler) { this.profiler = profiler != null ? profiler : new Profiler(false); } /** * Оценивает площадь заданной фигуры с помощью метода Монте-Карло. * <p> * Алгоритм: * <ol> * <li>Генерирует N случайных точек равномерно распределённых внутри прямоугольника</li> * <li>Подсчитывает количество точек, попавших внутрь фигуры (hits)</li> * <li>Вычисляет оценку площади: S_прямоугольника × (hits / N)</li> * <li>Вычисляет относительную ошибку относительно точной площади</li> * </ol> * * @param figure геометрическая фигура, площадь которой оценивается * @param rectangle ограничивающий прямоугольник, содержащий фигуру * @param n количество случайных выборок (испытаний) * @param rng генератор случайных чисел * @return результат оценки методом Монте-Карло, содержащий количество попаданий, * оценённую площадь, относительную ошибку и время выполнения * @throws IllegalArgumentException если figure или rectangle равны null */ public MonteCarloResult estimateArea(Figure figure, Rectangle rectangle, long n, Random rng) { if (figure == null) { throw new IllegalArgumentException("Figure не может быть null"); } if (rectangle == null) { throw new IllegalArgumentException("Rectangle не может быть null"); } if (rng == null) { throw new IllegalArgumentException("Random generator не может быть null"); } if (n <= 0) { return new MonteCarloResult(0L, 0L, 0.0, 0.0, 0L); } Stopwatch sw = new Stopwatch(); sw.start(); if (profiler.isEnabled()) { profiler.startOperation("MonteCarlo.estimateArea"); } try { double[] bounds = rectangle.getBounds(); double minX = bounds[0]; double maxX = bounds[1]; double minY = bounds[2]; double maxY = bounds[3]; long hits = generatePointsAndCountHits(figure, minX, maxX, minY, maxY, n, rng); double rectArea = rectangle.area(); double estimatedArea = calculateEstimatedArea(rectArea, hits, n); double exactArea = figure.exactArea(); double relativeErrorPercent = calculateRelativeError(estimatedArea, exactArea); long durationMillis = sw.stop(); if (profiler.isEnabled()) { profiler.endOperation("MonteCarlo.estimateArea", sw); } return new MonteCarloResult(n, hits, estimatedArea, relativeErrorPercent, durationMillis); } catch (Exception e) { if (sw.isRunning()) { sw.stop(); } throw e; } } /** * Генерирует случайные точки и подсчитывает количество попаданий в фигуру. * * @param figure фигура для проверки попаданий * @param minX минимальная X-координата * @param maxX максимальная X-координата * @param minY минимальная Y-координата * @param maxY максимальная Y-координата * @param n количество точек для генерации * @param rng генератор случайных чисел * @return количество точек, попавших внутрь фигуры */ private long generatePointsAndCountHits(Figure figure, double minX, double maxX, double minY, double maxY, long n, Random rng) { long hits = 0L; for (long i = 0; i < n; i++) { double x = minX + rng.nextDouble() * (maxX - minX); double y = minY + rng.nextDouble() * (maxY - minY); Point p = new Point(x, y); if (figure.contains(p)) { hits++; } } return hits; } /** * Вычисляет оценку площади на основе доли попаданий. * * @param rectArea площадь ограничивающего прямоугольника * @param hits количество попаданий * @param n общее количество испытаний * @return оценка площади фигуры */ private double calculateEstimatedArea(double rectArea, long hits, long n) { return rectArea * ((double) hits / (double) n); } /** * Вычисляет относительную ошибку в процентах. * * @param estimatedArea оценка площади * @param exactArea точная площадь * @return относительная ошибка в процентах (0.0, если exactArea = 0) */ private double calculateRelativeError(double estimatedArea, double exactArea) { if (exactArea > 0.0) { return Math.abs(estimatedArea - exactArea) / exactArea * 100.0; } else { // При нулевой площади указываем ошибку 0 return 0.0; } } }