使用double
s我希望有大约15个小数点的精度。我知道很多十进制数是not exactly representable in floating point notation,所以我会得到1/3
的近似值。但是,使用double
我会期望近似值大约为15个小数点。我还希望在算术时保持这种准确度。
但是,在下面的示例中,我尝试使用由Heron's formula支持的OpenMesh::VectorDataT<double,3>
和OpenMesh::Vec3d
来计算三角形的面积,最终结果只是准确的到5个小数点。
正确的结果是area = 8.19922e-8
,但我得到area=8.1992238711962083e-8
。有什么想法来自哪里?
这可能是由Heron公式中的不稳定性造成的,这是一个很好的建议,但不幸的是在这个例子中并非如此。我添加了代码,可以为那些可能感兴趣的人计算Heron的稳定变化。在此示例中,u.norm()>v.norm()>w.norm()
。
#include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh>
int main()
{
//triangle vertices
OpenMesh::Vec3d x(0.051051, 0.057411, 0.001355);
OpenMesh::Vec3d y(0.050981, 0.057337, -0.000678);
OpenMesh::Vec3d z(0.050949, 0.057303, 0.0);
//edge vectors
OpenMesh::Vec3d u = x-y;
OpenMesh::Vec3d v = x-z;
OpenMesh::Vec3d w = y-z;
//Heron's Formula
double semiP = (u.norm() + v.norm() + w.norm())/2.0;
double area = sqrt(semiP * (semiP - u.norm()) * (semiP - v.norm()) * (semiP - w.norm()) );
//Heron's Formula for small angles
double areaSmall = sqrt((u.norm() + (v.norm()+w.norm()))*(w.norm()-(u.norm()-v.norm()))*(w.norm()+(u.norm()-v.norm()))*(u.norm()+(v.norm()-w.norm())))/4.0;
}
答案 0 :(得分:3)
苍鹭的公式在数值上不稳定。如果你有一个非常“扁平”的三角形,角度很小,那么两个小边的总和几乎就是长边,所以其中一个术语变得非常小。例如,如果a
和b
是小方,
(s - c)
会非常小,因为
s = (a + b + c)/2
几乎等于c
。
wikipedia article about herons formula提到了一个稳定的选择:
安排双方a > b > c
并使用
A = 1/4*sqrt((a + (b + c))*(c - (a - b))*(c + (a - b))*(a + (b - c)))
答案 1 :(得分:3)
小数点后75位,三角形的正确区域为
0.000000081992238711963087279421583920293974467992093148008322378721298327364.
如果我用它们的十进制等值替换九个double
常量,我得
0.000000081992238711965902754749500279615357792172906541206211853522524016959
看起来你没有得到你所期待的东西,因为你期待一些不合理的东西。
答案 2 :(得分:2)
如果值完全相互接近,任何涉及减法的计算都将导致精度损失。你对这次减法有多少有效数字?
1.23456789012345
- 1.23456789000000
----------------
0.00000000012345
两个操作数都有15位精度,但结果只有5位。