【发布时间】:2019-10-28 11:27:22
【问题描述】:
我想到了一种积分计算算法,它应该比常规矩形方法更准确。我的算法最好用图形来描述(我以 f(x) = sin(x) 为例):
首先点 P1、P2、P3、P4 的 x 和 y 位置是 计算(红点)。
绿色四边形的区域是结果的一部分。 该面积是通过将其分成两个三角形(蓝色 行)。
每个三角形的面积是使用 Heron 公式计算的。
我认为这显然会比矩形方法产生更好的结果。
在代码中是这样的:
double integral(double f(double x), double min, double max) {
Point p1, p2, p3, p4;
double area = 0.0;
double s1 = 0.0;
double s2 = 0.0;
for(double x = min; x < max; x += stepSize) {
p1.x = x;
p1.y = 0.0;
p2.x = x;
p2.y = f(x);
p3.x = x + stepSize;
p3.y = f(x + stepSize);
p4.x = x + stepSize;
p4.y = 0.0;
s1 = 0.5 * (distance(p1, p2) + distance(p2, p4) + distance(p1, p4));
s2 = 0.5 * (distance(p2, p3) + distance(p3, p4) + distance(p2, p4));
area += sqrt(s1 * (s1 - distance(p1, p2)) * (s1 - distance(p2, p4)) * (s1 - distance(p1, p4)));
area += sqrt(s2 * (s2 - distance(p2, p3)) * (s2 - distance(p3, p4)) * (s2 - distance(p2, p4)));
}
return area;
}
distance 函数只是返回二维空间中两点之间的距离。 Point 结构只是保存一个 x 和 y 坐标。 stepSize 是一个常量,我设置为 0.001
我的函数给出的结果是正确的,但我想知道它与矩形方法相比要精确多少。
在互联网上我找到了使用矩形计算积分的代码:
double integral2(double(*f)(double x), double a, double b, int n) {
double step = (b - a) / n; // width of each small rectangle
double area = 0.0; // signed area
for (int i = 0; i < n; i ++) {
area += f(a + (i + 0.5) * step) * step; // sum up each small rectangle
}
return area;
}
我都使用标准 math.h sin 函数从 0.0 到半 π 对它们进行了测试。这个面积应该是1。
我的算法给出了1.000204 步长为0.001 的结果。
矩形算法给我的结果是1.000010,计算出的步长为0.015708。
如何解释精度和步长上的这种差异? 我的算法是不是执行错了?
更新
使用第二种方法的计算步长,我得到的结果0.999983 比步长为0.001 的结果更接近一。
现在怎么会这样??
【问题讨论】:
-
标准浮点舍入问题?详情见Is floating point math broken?
-
@Someprogrammerdude 我确保所有函数都只使用双打
-
我会计算梯形的面积而不将它们分成三角形。这将减少浮点运算的数量,并随之减少舍入误差。
-
与零阶矩形相比,您使用的是一阶方法。主要区别在于矩形用分段常数函数(0 阶)逼近函数,而用分段线性函数(1 阶)逼近函数。使 dx 足够小,它们都会收敛到相同的结果,但你的收敛速度会更快
-
我将此问题添加到我的收藏夹,希望我能抽出时间写一个易于理解的答案,只是现在没有时间