Я опишу решение задачи численного поиска площади фигуры, ограниченной системой неравенств. Задача решена в учебных целях. Программа написана на Java с использованием Swing в среде NetBeans. Исходные данные следующие (приведены для примера). Есть система неравенств, ограничивающих фигуру:
Есть координаты точки, принадлежащей этой фигуре: x=0,75; y=1,25.
Требуется найти площадь фигуры. Графически условия задачи выглядят так:
В проекте я использовал библиотеки:
commons-math3-3.0.jar
commons-lang-2.6.jar
jfreechart-1.0.14.jar
jcommon-1.0.17.jar
orson-0.5.0.jar
и глобальную библиотеку JDK 1.7.
Я создал класс Point, который содержит координаты точки и признак принадлежности фигуре:
Затем я создал класс MethodMonteCarlo с классами, содержащими четыре неравенства f0, f1, f2 и f3 (Вы можете заменить и произвольно расширить перечень неравенств):
Здесь в методе run() используется генератор псевдослучайных чисел generator.nextDouble().
В этом методе я использовал генерирование 10 тысяч точек. Вы можете выбрать любое количество.
И затем создал класс MainJFrame:
И главный класс Main:
В результате, при запуске приложения открывается окно:
При нажатии кнопки Расчёт запускается итерация, на каждом шаге которой каждая граница (верхняя, нижняя, левая, правая), начиная с +/-0,1 (в абсолютных единицах) относительно заданной внутренней точки, расширяется на 5% (в 1,05 раза) до тех пор, пока отношение ширины (высоты) расширяемой области по отношению к ширине (высоте) интервала не достигнет 105% (это определено константой public static double COEFF = 0.05):
Здесь видно, какую площадь занимает фигура: 51,40.
Площадь вычисляется так:
(количество попавших в фигуру точек / количество точек в прямоугольнике) * (площадь описывающего прямоугольника).
Исходный код этого проекта доступен по ссылке mmc.zip. Для скачивания файла после перехода по ссылке выберите пункт меню Файл > Загрузить.
Вы можете использовать этот код свободно, без каких-либо лицензионных ограничений!
Есть координаты точки, принадлежащей этой фигуре: x=0,75; y=1,25.
Требуется найти площадь фигуры. Графически условия задачи выглядят так:
В проекте я использовал библиотеки:
commons-math3-3.0.jar
commons-lang-2.6.jar
jfreechart-1.0.14.jar
jcommon-1.0.17.jar
orson-0.5.0.jar
и глобальную библиотеку JDK 1.7.
Я создал класс Point, который содержит координаты точки и признак принадлежности фигуре:
package mmc;
public class Point {
private double x;
private double y;
private boolean inside;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
public boolean getInside() {
return inside;
}
public void setInside(boolean inside) {
this.inside = inside;
}
}
package mmc;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math3.analysis.UnivariateFunction;
import org.apache.commons.math3.stat.StatUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.math3.random.MersenneTwister;
public class MethodMonteCarlo {
public static double COEFF = 0.05;
private Point insidePoint, leftBottom, rightTop;
private MersenneTwister generator;
private double percent;
private interface Func extends UnivariateFunction {
boolean contains(Point p);
}
private static class f0 implements Func {
public boolean contains(Point p) {
return p.getY() - value(p.getX()) > 0;
}
public double value(double x) {
return Math.pow(x, 2)+0.1;
}
}
private static class f1 implements Func {
public boolean contains(Point p) {
return p.getY() - value(p.getX()) < 0;
}
public double value(double x) {
return 8 * Math.pow(x, 2);
}
}
private static class f2 implements Func {
public boolean contains(Point p) {
return p.getY() - value(p.getX()) < 0;
}
public double value(double x) {
return -2 * x + 3;
}
}
private static class f3 implements Func {
public boolean contains(Point p) {
return p.getY() - value(p.getX()) > 0;
}
public double value(double x) {
return -10 * x + 5;
}
}
private Func[] func;
public MethodMonteCarlo(Point insidePoint) {
percent = 100d;
generator = new MersenneTwister();
func = new Func[] { new f0(), new f1(), new f2(), new f3() };
this.insidePoint = insidePoint;
leftBottom = new Point(insidePoint.getX() - 0.1, insidePoint.getY() - 0.1);
rightTop = new Point(insidePoint.getX() + 0.1, insidePoint.getY() + 0.1);
}
public Point getInsidePoint() {
return insidePoint;
}
public Point getLeftBottom() {
return leftBottom;
}
public Point getRightTop() {
return rightTop;
}
private double min(Double[] d) {
return d.length > 0 ? StatUtils.min(ArrayUtils.toPrimitive(d)) : Double.MAX_VALUE;
}
private double max(Double[] d) {
return d.length > 0 ? StatUtils.max(ArrayUtils.toPrimitive(d)) : -Double.MAX_VALUE;
}
public double getPercent() {
return percent;
}
private Double[] toDoubleArray(Point[] points, boolean inside, boolean xAxis) {
List d = new ArrayList();
for (int i = 0; i < points.length; i++)
if ((inside && points[i].getInside()) || (!inside && !points[i].getInside()))
d.add(xAxis ? points[i].getX() : points[i].getY());
return d.toArray(new Double[0]);
}
public boolean checkLeft(Point[] points) {
double minInside = min(toDoubleArray(points, true, true));
double minOutside = min(toDoubleArray(points, false, true));
double maxInside = max(toDoubleArray(points, true, true));
double width = maxInside - minInside;
return minInside - minOutside > COEFF * width;
}
public boolean checkRight(Point[] points) {
double maxInside = max(toDoubleArray(points, true, true));
double maxOutside = max(toDoubleArray(points, false, true));
double minInside = min(toDoubleArray(points, true, true));
double width = maxInside - minInside;
return maxOutside - maxInside > COEFF * width;
}
public boolean checkBottom(Point[] points) {
double minInside = min(toDoubleArray(points, true, false));
double minOutside = min(toDoubleArray(points, false, false));
double maxInside = max(toDoubleArray(points, true, false));
double height = maxInside - minInside;
return minInside - minOutside > COEFF * height;
}
public boolean checkTop(Point[] points) {
double maxInside = max(toDoubleArray(points, true, false));
double maxOutside = max(toDoubleArray(points, false, false));
double minInside = min(toDoubleArray(points, true, false));
double height = maxInside - minInside;
return maxOutside - maxInside > COEFF * height;
}
private boolean contains(int index, Point p) {
return func[index].contains(p);
}
private boolean contains(Point p) {
boolean result = true;
for (int i = 0; i < func.length; i++) {
if (!contains(i, p)) {
result = false;
break;
}
}
p.setInside(result);
return result;
}
public Point[] run() {
int count = 10000;
double insidePoints = 0;
Point[] points = new Point[count];
for (int i = 0; i < count; i++) {
double x = leftBottom.getX() + generator.nextDouble() * (rightTop.getX() - leftBottom.getX());
double y = leftBottom.getY() + generator.nextDouble() * (rightTop.getY() - leftBottom.getY());
points[i] = new Point(x, y);
if (contains(points[i]))
insidePoints++;
}
percent = 100d * (insidePoints / count);
return points;
}
}
В этом методе я использовал генерирование 10 тысяч точек. Вы можете выбрать любое количество.
И затем создал класс MainJFrame:
package mmc;
import org.jfree.data.xy.*;
public class MainJFrame extends javax.swing.JFrame {
private MethodMonteCarlo methodMonteCarlo;
public MainJFrame() {
initComponents();
methodMonteCarlo = new MethodMonteCarlo(new Point(0.75, 1.25));
setLocationRelativeTo(null);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
...
}//
private void quitJButtonActionPerformed(java.awt.event.ActionEvent evt) {
System.exit(0);
}
private void appendString(final String s) {
new Thread(new Runnable(){
public void run() {
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run() {
jTextArea1.append(s);
}
});
}
}).start();
}
private void runJButtonActionPerformed(java.awt.event.ActionEvent evt) {
double coeff = 1 + MethodMonteCarlo.COEFF;
Point[] points;
Point insidePoint = methodMonteCarlo.getInsidePoint();
boolean left, right, bottom, top;
Point leftBottom = methodMonteCarlo.getLeftBottom();
Point rightTop = methodMonteCarlo.getRightTop();
do {
points = methodMonteCarlo.run();
appendString(String.format("Доля точек в области = %.2f%% \n", methodMonteCarlo.getPercent()));
left = methodMonteCarlo.checkLeft(points);
right = methodMonteCarlo.checkRight(points);
bottom = methodMonteCarlo.checkBottom(points);
top = methodMonteCarlo.checkTop(points);
if (!left) {
leftBottom.setX(insidePoint.getX() - coeff * (insidePoint.getX() - leftBottom.getX()));
appendString(String.format("Мин. X = %.2f \n", leftBottom.getX()));
}
if (!right) {
rightTop.setX(insidePoint.getX() + coeff * (rightTop.getX() - insidePoint.getX()));
appendString(String.format("Макс. X = %.2f \n", rightTop.getX()));
}
if (!bottom) {
leftBottom.setY(insidePoint.getY() - coeff * (insidePoint.getY() - leftBottom.getY()));
appendString(String.format("Мин. Y = %.2f \n", leftBottom.getY()));
}
if (!top) {
rightTop.setY(insidePoint.getY() + coeff * (rightTop.getY() - insidePoint.getY()));
appendString(String.format("Макс. Y = %.2f \n", rightTop.getY()));
}
} while (!left || !right || !bottom || !top);
drawChart(points);
double area = methodMonteCarlo.getPercent() * (rightTop.getX() - leftBottom.getX()) * (rightTop.getY() - leftBottom.getY());
appendString(String.format("Площадь = %.2f \n", area));
}
private void drawChart(Point[] points) {
final XYSeries series0 = new XYSeries("outer");
final XYSeries series1 = new XYSeries("inner");
for (int i = 0; i < points.length; i++) {
if (points[i].getInside()) {
series1.add(points[i].getX(), points[i].getY());
} else {
series0.add(points[i].getX(), points[i].getY());
}
}
final XYSeriesCollection dataset = new XYSeriesCollection();
dataset.addSeries(series0);
dataset.addSeries(series1);
scatterChart.setDataset(dataset);
}
}
с соответствующей формой:И главный класс Main:
/*
* Метод Монте-Карло
*/
package mmc;
import javax.swing.UIManager;
public class Main {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainJFrame().setVisible(true);
}
});
}
}
При нажатии кнопки Расчёт запускается итерация, на каждом шаге которой каждая граница (верхняя, нижняя, левая, правая), начиная с +/-0,1 (в абсолютных единицах) относительно заданной внутренней точки, расширяется на 5% (в 1,05 раза) до тех пор, пока отношение ширины (высоты) расширяемой области по отношению к ширине (высоте) интервала не достигнет 105% (это определено константой public static double COEFF = 0.05):
Здесь видно, какую площадь занимает фигура: 51,40.
Площадь вычисляется так:
(количество попавших в фигуру точек / количество точек в прямоугольнике) * (площадь описывающего прямоугольника).
Исходный код этого проекта доступен по ссылке mmc.zip. Для скачивания файла после перехода по ссылке выберите пункт меню Файл > Загрузить.
Вы можете использовать этот код свободно, без каких-либо лицензионных ограничений!
Здравствуйте, подскажите как распараллелить программу, которая будет рассчитывать соотношения площадей двух концентрических окружностей (R1 < R2)?
ОтветитьУдалить