Очень нуждаюсь в помощи по написанию программы для вычисления кратных интегралов методом Монте-Карло
читать дальшеЯзык - любой, кроме С# и паскаля. Цель такова - вводим параметры (подинтегральную функцию (для реализации чего, как я понял, нужен интерпритатор), пределы интегрирования), n (для точности), получаем число-ответ.
@темы:
Алгоритм,
Монте-Карло,
численное интегрирование,
PHP
Сам по себе этот метод интегрирования относительно простой, по сравнению с написанием интерпретатора (если не усложнять метод, например, собственным законом распределения для случайных точек), так что, как я понимаю, основная задача состоит в написании интерпретатора. Я пару лет назад в учебных целях писал интерпритатор, там были только 4 операции (+-*/) но он был построен так, что добавить другие было не проблемой. Сейчас этой программы уже нет, но суть его работы можно пояснить так:
1+2*(3+2*2)
1+2*(3+4)
1+2*(7)
1+2*7
1+14
15
Тоесть задача решается пошагово. И постепенно выражение упрощается. На каждом шаге либо выполняется одна из операции, либо раскрываются скобки.
Может быть метод и не самый оптимальный, но мне понравился, т.к. позволяет написать достаточно прозрачный код и добавлять, при необходимости, новые операции.
Начать нужно с парсинга входной строки с выражением: разбиваете ее на массив, в каждом элементе которого - или число, или код операции (можно создать второй массив, если в нем элемент = 1, то соответствующий элемент в первом массиве - код операции, иначе - число). Такая подготовка упростит дальнейшие проходы. Например для приведенного примера массивы могут выглядеть так (+ это 1, * - это 2, скобки это 3 и 4):
1 1 2 2 3 3 1 2 2 2 4
0 1 0 1 1 0 1 0 1 0 1
Попробуйте начать это решать, а будут вопросы - задавайте.
В Edit1 вводим выражение, в заголовке формы получаем ответ.
#include
int main(void)
{
char *expr = "10*50*$x";
char *cmd = new char[256];
sprintf(cmd, "let x=10; let y=%s; echo $y", expr);
FILE *out = popen(cmd, "r");
while(!feof(out))
{
char outc = ((char)getc(out));
printf("%c", outc);
}
return 0;
}
так что необходимость делать интерпритатор очень опциональна
Если посмотреть исходный код VCL в Delphi, то можно убедиться, что она расчитана как на Windows, так и на Linux. Просто дважды нужно будет скомпилировать один и тот же код - сначала в Delphi а потом в его аналоге в Linux.
Java, Php - кроссплатформенные.
ИМХО и C++ можно использовать, только скомпилировать дважды.
Мне кажется, что вам было бы удобнее всего использовать PHP. Считаете выражение через eval, как сказал Vj_o-oy а потом генерируете n точек. Если не нужна очень высокая производительность, конечно.
Эта функция позволяет выполнить код, который хранится в строке, которая передается в качестве аргумента: http://php.su/functions/?eval
Вы бы хоть прочитали, что я вам предложил в посте от 2010-05-12 в 19:25. Все, что от вас требуется, это понять алгоритм, подкорректировать его для вашей задачи и перевести на PHP.
Program pmk;
Uses crt;
Var k,p,s,g,x,Integral : real;
n,i,a,b : integer;
BEGIN
writeln(‘Введите промежуток интегрирования (a;b):’);
readln(a);
readln(b);
writeln(‘Введите количество случайных значений(число испытаний):’);
readln(n);
k:=b-a; {Переменной“k”присвоим значение длины промежутка интегрирования}$
writeln(‘k=’,k);
for i:= 1 to n do begin {проведем n испытаний}
g:=random; {g – переменная вещественного типа, случайная величина из промежутка [0;1]}
x:= a + g*(b-a); {По этой формуле получается произвольная величина из [a; b] }
s:=s + (1+x); {s:=s +(x*x)} {Вообще можно подставить любую функцию}
delay(1000); {задержка, чтобы произвольные значения не повторялись}
end; {конец испытаний}
writeln(‘s=’,s); {Сумма функции для n произвольных значений}
Integral:=(1/n)*k*s ;
writeln(‘Интеграл=’,Integral);
readln;
END.
А вот что я из этого попытался сделать на PHP (не смейтесь только
Калькулятор
<?php
$a=$_GET['a'];
$b=$_GET['b'];
$c=$_GET['c'];
$k=$b-$a;
$g=lcg_value();
$x=$a+$g*($b-$a);
$s=$s+(1+$x);
$z=(1/$n)*$k*$s;
echo "$z";
?>
Введите a:
Введите b:
Введите количество случайных значений:
Сразу видно - код кривейший, но тем не менее. Если пойму это, что попроще, то пойму и как сделать кратные. Eval пока не использовал, подинтегральная функция f(x)=1+x
Этот код можно перевести на PHP примерно так:
http://paste.org.ru/?orz2o2
А для трехмерного пространства, например, нужно будет уже сгенерировать две переменные $g - одну для координаты x, а другую - для y. И т.д.
paste.org.ru/?j5pcvx
входную функцию вводите в таком виде: 1 + $x т.е. переменную со знаком "$"
Не работает. Запускаю - говорит деление на ноль в строке 18. Видимо, все зависит от настроек сервера. У меня такую ошибку не выдавал.
Вычисление: то же самое, что и для интеграла по x, но только теперь уже будет интеграл по x1, x2, x3, x4, ... При этом для каждой точки нужно будет сгенерировать не одну, а несколько координат:
$g=lcg_value();
$x1=$a1+$g*($b1-$a1);
$g=lcg_value();
$x2=$a2+$g*($b1-$a2);
...
eval ("\$y = $d;");
$s=$s+$y;
Под конец считаем:
$z=(1/$c)*($k1+$k2+$k3+...)*$s;
Если измерений может быть много, то, наверное, можно организовать массивы a[] и b[], считывая их, например, из memo - но это уже дело вкуса. Тогда x1, x2, x3... можно заменить массивом x[], и входная функция будет иметь вид: $x[2]-10*$x[1]+$x[3]...
eval ("\$a = $u;");
eval ("\$b = $v;");
"Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\index.php(9) : eval()'d code on line 1
Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\index.php(11) : eval()'d code on line 1"
UPD Переместил строки
eval ("\$a = $u;");
eval ("\$b = $v;");
$k=$b-$a;
в цикл, заработало без всяких ошибок, но тут попахивает уже неоптимизированностью, как этого избежать не внося в цикл?
integraly.ru/integral-base/vychislit-dvoinoi-in...
integraly.ru/integral-base/vychislit-dvoinoi-in...
То есть с неясно заданными границами интегрирования.
У меня сосчитал cos(3.14) = примерно -1, т.е. функции вызывает.
в цикл, заработало без всяких ошибок
Вы в границы интегрирования случайно переменные ($x, $y и т.д.) не подставляете? Они на момент вызова первых двух evalue не определены.
Можно ли как-то в нем реализовать быстрое решение таких интегралов
Посмотрите, как берется первый интеграл - он раскладывается на 2 интеграла.
Какая цель написания этой программы, если не секрет? Если задача не учебная, и требуется быстрая и точная реализация, то может быть стоит посмотреть в сторону уже готовых решений? Наверняка такие найдутся, может быть даже кроссплатформенные.
У меня сосчитал cos(3.14) = примерно -1, т.е. функции вызывает.
в цикл, заработало без всяких ошибок
Вы в границы интегрирования случайно переменные ($x, $y и т.д.) не подставляете? Они на момент вызова первых двух evalue не определены.
переменные, естественно, не подставлял. Без цикла уже работает, но эти две ошибки остались (Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\index.php(9) : eval()'d code on line 1
Parse error: syntax error, unexpected ';' in Z:\home\localhost\www\index.php(11) : eval()'d code on line 1). Хотелось бы избавиться от них...
Какая цель написания этой программы, если не секрет? Если задача не учебная, и требуется быстрая и точная реализация, то может быть стоит посмотреть в сторону уже готовых решений? Наверняка такие найдутся, может быть даже кроссплатформенные.
задача сугубо учебная, поэтому разобраться в этом должен сам
Допустим вы знаете, что пользователь может ввести переменные x1, x2, ... Тогда значок $ можно добавить после запуска программы:
string str_replace('x1', '\$x1', $d);
string str_replace('x2', '\$x2', $d);
string str_replace('x3', '\$x3', $d);