/
onequ1z
/
JavaCoursePaperTulSU
Обзор
Документация
Войти
/
onequ1z
/
JavaCoursePaperTulSU
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
src/main/java/ru/dmitry/montecarlo/App.java
271 строка
14 KB
tayno
Добавлено AvgTime для итоговой таблицы
08 дек 2025, 13:07
08 дек 2025, 13:07
ffd7c03
Код
Авторство
О чём код?
package ru.dmitry.montecarlo; import ru.dmitry.montecarlo.model.ExperimentResult; import ru.dmitry.montecarlo.model.MonteCarloResult; import ru.dmitry.montecarlo.model.Point; import ru.dmitry.montecarlo.model.Rectangle; import ru.dmitry.montecarlo.model.TriangleGEF; import ru.dmitry.montecarlo.service.ExperimentRunner; import ru.dmitry.montecarlo.service.MonteCarlo; import ru.dmitry.montecarlo.service.MonteCarloEstimator; import ru.dmitry.montecarlo.service.MonteCarloParallel; import ru.dmitry.montecarlo.util.AppConfig; import ru.dmitry.montecarlo.util.ArgumentParser; import ru.dmitry.montecarlo.util.CsvExporter; import java.io.IOException; import java.util.Random; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; /** * Главный класс приложения для приближённого вычисления площади методом Монте-Карло. * <p> * Приложение поддерживает два режима работы: * <ul> * <li><b>quick</b> - быстрый режим с одним запуском Монте-Карло</li> * <li><b>experiment</b> - режим экспериментов с множественными запусками и статистикой</li> * </ul> * <p> * Фигура для оценки площади - треугольник G-E-F, заданный внутри ограничивающего прямоугольника. * Координаты треугольника масштабируются пропорционально размерам прямоугольника. */ public class App { private static final Logger logger = Logger.getLogger(App.class.getName()); /** * Точка входа в приложение. * <p> * Парсит аргументы командной строки, настраивает логирование, создаёт геометрические фигуры * и запускает оценку площади методом Монте-Карло в зависимости от выбранного режима. * * @param args аргументы командной строки (см. {@link ArgumentParser#printHelp()}) */ public static void main(String[] args) { // Настройка логирования (по умолчанию INFO) setupLogging(false); AppConfig config; try { config = ArgumentParser.parse(args); } catch (IllegalArgumentException e) { System.err.println("Error parsing arguments: " + e.getMessage()); System.err.println(); ArgumentParser.printHelp(); System.exit(0); return; // для компилятора } // Настройка verbose логирования, если требуется if (config.isVerbose()) { setupLogging(true); } logger.info("Monte Carlo Area Approximation - Starting"); logger.fine("Configuration: " + config.getMode() + " mode, rect=[" + config.getRectX0() + "," + config.getRectY0() + "] to [" + config.getRectX1() + "," + config.getRectY1() + "], threads=" + config.getThreads()); // Создание прямоугольника из конфигурации // По умолчанию: A(0,0), B(0,4), C(12.8,4), D(12.8,0) Point a = new Point(config.getRectX0(), config.getRectY0()); Point b = new Point(config.getRectX0(), config.getRectY1()); Point c = new Point(config.getRectX1(), config.getRectY1()); Point d = new Point(config.getRectX1(), config.getRectY0()); Rectangle rectangle = new Rectangle(a, b, c, d); // Создание фигуры (треугольник G-E-F) // Координаты треугольника G-E-F: // G = (0, 3), E = (9.2, 4), F = (5.3, 0) // Для произвольного прямоугольника масштабируем пропорционально double defaultWidth = 12.8; double defaultHeight = 4.0; double width = rectangle.width(); double height = rectangle.height(); double scaleX = width / defaultWidth; double scaleY = height / defaultHeight; // Базовые координаты треугольника для прямоугольника (0,0)-(12.8,4) double baseGx = 0.0; double baseGy = 3.0; double baseEx = 9.2; double baseEy = 4.0; double baseFx = 5.3; double baseFy = 0.0; // Масштабируем и сдвигаем относительно начала координат прямоугольника Point g = new Point(config.getRectX0() + baseGx * scaleX, config.getRectY0() + baseGy * scaleY); Point e = new Point(config.getRectX0() + baseEx * scaleX, config.getRectY0() + baseEy * scaleY); Point f = new Point(config.getRectX0() + baseFx * scaleX, config.getRectY0() + baseFy * scaleY); TriangleGEF triangle = new TriangleGEF(g, e, f); // Создание генератора случайных чисел Random rng = config.getSeed() != null ? new Random(config.getSeed()) : new Random(); if (config.getSeed() != null) { logger.fine("Using seed: " + config.getSeed()); } // Запуск в зависимости от режима if ("experiment".equals(config.getMode())) { runExperimentMode(rectangle, triangle, config, rng); } else { runDemoMode(rectangle, triangle, config, rng); } logger.info("Application completed successfully"); } /** * Настраивает логирование программно. * Сбрасывает текущую конфигурацию логирования и устанавливает новый уровень * с консольным обработчиком. * * @param verbose если true, устанавливает уровень FINE для подробного логирования, * иначе INFO для обычного логирования */ private static void setupLogging(boolean verbose) { LogManager.getLogManager().reset(); Logger rootLogger = Logger.getLogger(""); rootLogger.setLevel(verbose ? Level.FINE : Level.INFO); // Настройка консольного handler java.util.logging.ConsoleHandler consoleHandler = new java.util.logging.ConsoleHandler(); consoleHandler.setLevel(verbose ? Level.FINE : Level.INFO); consoleHandler.setFormatter(new java.util.logging.SimpleFormatter()); rootLogger.addHandler(consoleHandler); } /** * Запускает быстрый режим демонстрации. * Выполняет один запуск метода Монте-Карло и выводит результаты в консоль. * * @param rectangle ограничивающий прямоугольник * @param triangle треугольник G-E-F для оценки площади * @param config конфигурация приложения * @param rng генератор случайных чисел */ private static void runDemoMode(Rectangle rectangle, TriangleGEF triangle, AppConfig config, Random rng) { System.out.println("Rectangle bounds for gef test figure:"); System.out.println(" Corner A: " + rectangle.getA()); System.out.println(" Corner B: " + rectangle.getB()); System.out.println(" Corner C: " + rectangle.getC()); System.out.println(" Corner D: " + rectangle.getD()); System.out.println(" Width: " + rectangle.width()); System.out.println(" Height: " + rectangle.height()); System.out.println(" Rectangle Area: " + rectangle.area()); System.out.println("\nTriangle G-E-F:"); System.out.println(" Point G: " + triangle.getG()); System.out.println(" Point E: " + triangle.getE()); System.out.println(" Point F: " + triangle.getF()); System.out.println(" Exact Area: " + triangle.exactArea()); // Создаём оценщик в зависимости от количества потоков MonteCarloEstimator estimator = createEstimator(config); long samples = config.getSingleN(); logger.fine("Running Monte Carlo with N=" + samples + ", threads=" + config.getThreads()); MonteCarloResult result = estimator.estimateArea(triangle, rectangle, samples, rng); System.out.println("\nMonte Carlo оценка (N = " + samples + "):"); System.out.println(" " + result); } /** * Запускает режим экспериментов. * Выполняет множественные запуски метода Монте-Карло для различных значений N, * агрегирует результаты и выводит статистику в виде таблиц. * * @param rectangle ограничивающий прямоугольник * @param triangle треугольник G-E-F для оценки площади * @param config конфигурация приложения * @param rng генератор случайных чисел */ private static void runExperimentMode(Rectangle rectangle, TriangleGEF triangle, AppConfig config, Random rng) { System.out.println("Experiment mode: повторные эксперименты Монте-Карло"); System.out.println("Rectangle ABCD: A=" + rectangle.getA() + ", B=" + rectangle.getB() + ", C=" + rectangle.getC() + ", D=" + rectangle.getD()); System.out.println("Triangle GEF: G=" + triangle.getG() + ", E=" + triangle.getE() + ", F=" + triangle.getF()); System.out.println("Exact triangle area: " + triangle.exactArea()); long[] nValues = config.getNValuesArray(); int repeats = 6; logger.fine("Running experiments with N values: " + java.util.Arrays.toString(nValues) + ", repeats=" + repeats + ", threads=" + config.getThreads()); // Создаём оценщик в зависимости от количества потоков MonteCarloEstimator estimator = createEstimator(config); ExperimentRunner runner = new ExperimentRunner(estimator); ExperimentResult experimentResult = runner.runExperiments( triangle, rectangle, nValues, repeats, rng ); System.out.println(); System.out.println("Per-run results:"); System.out.printf("%-8s %-6s %-15s %-15s %-10s%n", "N", "Run", "EstimatedArea", "RelError(%)", "Time(ms)"); for (ExperimentResult.NStats stats : experimentResult.getStatsPerN()) { MonteCarloResult[] runs = stats.getRuns(); for (int i = 0; i < runs.length; i++) { MonteCarloResult r = runs[i]; System.out.printf("%-8d %-6d %-15.6f %-15.6f %-10d%n", stats.getSamples(), (i + 1), r.getEstimatedArea(), r.getRelativeErrorPercent(), r.getDurationMillis()); } } System.out.println(); System.out.println("Summary (per N):"); System.out.printf("%-8s %-15s %-15s %-15s %-15s %-15s%n", "N", "AvgArea", "StdArea", "AvgErr(%)", "StdErr(%)", "AvgTime(ms)"); for (ExperimentResult.NStats stats : experimentResult.getStatsPerN()) { System.out.printf("%-8d %-15.6f %-15.6f %-15.6f %-15.6f %-15.2f%n", stats.getSamples(), stats.getAvgEstimatedArea(), stats.getStdDevEstimatedArea(), stats.getAvgRelativeErrorPercent(), stats.getStdDevRelativeErrorPercent(), stats.getAvgDurationMillis()); } // Экспорт в CSV, если указан файл if (config.getOutputFile() != null) { try { CsvExporter.exportToCsv(experimentResult, triangle.exactArea(), config.getOutputFile()); System.out.println(); System.out.println("Результаты экспортированы в файл: " + config.getOutputFile()); logger.info("CSV export completed: " + config.getOutputFile()); } catch (IOException e) { System.err.println("Ошибка при экспорте в CSV: " + e.getMessage()); logger.severe("Failed to export CSV: " + e.getMessage()); } } } /** * Создаёт оценщик Монте-Карло в зависимости от конфигурации. * Если threads > 1, создаёт многопоточную версию, иначе однопоточную. * * @param config конфигурация приложения * @return оценщик Монте-Карло */ private static MonteCarloEstimator createEstimator(AppConfig config) { if (config.getThreads() > 1) { logger.fine("Using parallel Monte Carlo with " + config.getThreads() + " threads"); return new MonteCarloParallel(config.getThreads()); } else { logger.fine("Using single-threaded Monte Carlo"); return new MonteCarlo(); } } }