用Javascript實現了函數積分的演算法。
從計算結果可以看出,演算法精度受隨機數發生器的影響較大。
[javascript]
//Monte carro求給定函數的定積分
//給定一個函數
function f1(x, xmin, xmax)
{
if (x >= xmin && x <= xmax)
return x * x * Math.sqrt(1 + x * x * x) - 1;
}
function f2(x, xmin, xmax)
{
if (x >= xmin && x <= xmax)
return x * Math.log(1 + x);
}
function f3(x, xmin, xmax)
{
if (x >= xmin && x <= xmax)
return Math.sqrt(1 - x * x);
}
function f4(x, xmin, xmax)
{
if (x >= xmin && x <= xmax)
return Math.cos(x) - 0.9;
}
//取得函數的上下極限——其精確度影響很大---由於用於積分,故若y>0,底限0;若y<0,則高限0;若y穿越x軸,則不修改預設極限
function getLimit(func, xmin, xmax)
{
//邊界極限
var t1 = func(xmin, xmin, xmax), t2 = func(xmax, xmin, xmax);
var limit = {y0: Math.min(t1, t2), y1: Math.max(t1, t2)};
var delta = 1e-3, lastX, lastY;
for(var x = xmin, i = 0; x <= xmax; x += delta, i++)
{
y = func(x, xmin, xmax);
if (y < limit.y0)
limit.y0 = y;
if (y > limit.y1)
limit.y1 = y;
if (i == 0)
{
lastX = x;
lastY = y;
}
else
{
var tx = (lastX + x) / 2;
var ty = func(tx, xmin, xmax);
if (Math.abs(lastY) > Math.abs(y))
{
if (Math.abs(lastY) < Math.abs(ty))
{
lastX = tx;
lastY = ty;
if (ty < 0 && limit.y0 > ty)
limit.y0 = ty;
else if (ty >= 0 && limit.y1 <= ty)
limit.y1 = ty;
}
}
if (Math.abs(lastY) < Math.abs(y))
{
if (Math.abs(y) < Math.abs(ty))
{
lastX = tx;
lastY = ty;
if (ty < 0 && limit.y0 > ty)
limit.y0 = ty;
else if (ty >= 0 && limit.y1 <= ty)
limit.y1 = ty;
}
}
}
}
if (limit.y0 > 0)
limit.y0 = 0;
if (limit.y1 < 0)
limit.y1 = 0;
return limit;
}
//積分
function cumulate(func, N, xmin, xmax)
{
var limit = getLimit(func, xmin, xmax);
//console.log('Limit=', limit.y0, limit.y1);
var x, yr, y;
var cntA = 0, cntB = 0;
for(var i = 0; i < N; i++)
{
x = xmin + (xmax - xmin) * Math.random();
yr = limit.y0 + (limit.y1 - limit.y0) * Math.random();
y = func(x, xmin, xmax);
if ( y >= 0 && yr >= 0 && yr <= y)
cntA++;
else
if (y <= 0 && yr <= 0 && yr >= y)
cntB++;
}
//console.log('counts=', cntA, cntB);
return (cntA - cntB) * (xmax - xmin) * (limit.y1 - limit.y0) / N;
}
//測試
var t1, t2;
var rst;
var N = 1e7;
var fs = [f1, f2, f3, f4];
var ans = [-0.593682861167513, 0.25, Math.PI/4, -0.058529015192103493347497678369701];
for(var i = 0; i < 4; i++)
{
t1 = new Date();
rst = cumulate(fs[i], N, 0, 1);
t2 = new Date();
console.log('[', i, ']=', ans[i].toFixed(15), rst.toFixed(15), t2 - t1, 'ms');
}