我有几何算法,我正在努力解决浮点不准确问题。 例如,我正在计算一个点位于左/右/平面上(C#):
const double Epsilon = 1e-10;
internal double ComputeDistance(Vector3D v)
{
Vector3D normal = Plane.Normal;
Vertex v0 = Plane.Origin;
double a = normal.X;
double b = normal.Y;
double c = normal.Z;
double d = -(a * v0.X + b * v0.Y + c * v0.Z);
return a * v.X + b * v.Y + c * v.Z + d;
}
internal string DistanceSign(Vector3D v)
{
var distance = ComputeDistance(v);
return (distance > Epsilon ? "left" : (distance < -Epsilon ? "right" : "on"));
}
如代码所示,我使用固定的Epsilon值。
但我不相信这个固定的epsilon,因为我不知道浮点错误的大小。如果fp错误大于我的epsilon间隔,那么我的算法将失败。 我怎样才能让它健壮?我在互联网上搜索过但到目前为止还没有找到解决方案。我读过“每个计算机科学家应该知道的关于浮点算术的内容”,它描述了为什么会出现fp错误而不是如何实际解决它们。
修改
这是一个看似不起作用的shewchuk谓词:
double[] pa = {0, 0};
double[] pb = {2 * Double.Epsilon, 0};
double[] pc = { 0, Double.Epsilon };
Assert.IsTrue(GeometricPredicates.Orient2D(pa, pb, pc) > 0);
断言失败,因为Orient2D返回0.代码为here
EDIT2
是否应该可以通过使用机器epsilon来计算误差?根据维基百科,由于四舍五入,机器epsilon是一个上限。对于double,它是2 ^ -53。所以,当我接受它时,我有一个算术计算: double x = y + z 那么最大误差应该是2 ^ -53。这个事实不应该能够计算出合适的epsilon吗?所以两个重写我的方法:
double const Machine_Eps = 1.11022302462516E-16 // (2^-53)
double Epsilon = Machine_Eps;
internal double ComputeDistance(Vector3D v)
{
Vector3D normal = Plane.Normal;
Vertex v0 = Plane.Origin;
double a = normal.X;
double b = normal.Y;
double c = normal.Z;
// 3 multiplications + 2 additions = maximum of 5*Machine_Eps
double d = -(a * v0.X + b * v0.Y + c * v0.Z);
// 3 multiplications + 3 additions = maximum of 6*Machine_Eps
Epsilon = 11 * Machine_Eps;
return a * v.X + b * v.Y + c * v.Z + d;
}
internal string DistanceSign(Vector3D v)
{
var distance = ComputeDistance(v);
return (distance > Epsilon ? "left" : (distance < -Epsilon ? "right" : "on"));
}
好的,现在你可以告诉我我有多错。 :)