Numerical precision of implementation for convex quadrilateral area
我已经实现了一种计算r3中凸四边形面积的方法。这个方法很好用,但我在小数点后8位遇到了数值精度问题。看看这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | internal static double GetTriangleArea(double ax, double ay, double az, double bx, double by, double bz, double cx, double cy, double cz ) { /** * AB = B-A = (ux, uy, uz) * AC = C-A = (wx, wy, wz) * * S = 0.5*sqrt{(uy*wz - uz*wy)2 + (uz*wx - ux*wz)2 + (ux*wy - uy*wx)2} * */ var ux = bx - ax; var uy = by - ay; var uz = bz - az; var wx = cx - ax; var wy = cy - ay; var wz = cz - az; var t1 = uy*wz - uz*wy; var t2 = uz*wx - ux*wz; var t3 = ux*wy - uy*wx; var s = 0.5*Math.Sqrt(t1*t1 + t2*t2 + t3*t3); return s; } internal static double GetConvexQuadrilateralArea(double ax, double ay, double az, double bx, double by, double bz, double cx, double cy, double cz, double dx, double dy, double dz) { var triangle1 = GetTriangleArea(ax, ay, az, bx, by, bz, cx, cy, cz); var triangle2 = GetTriangleArea(ax, ay, az, cx, cy, cz, dx,dy,dz); return triangle1 + triangle2; } |
这就是测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | [TestMethod] public void ParallelogramOfBaseBAndHeightHMustHaveAreaEqualToBTimesH() { var random = new Random(1); const double scale = 10000; for (var counter = 0; counter < 1000; counter++) { double baseLength = random.NextDouble() * scale; double height = random.NextDouble() * scale; double dx = random.NextDouble()*scale; var a = new[] { 0, 0, 0 }; var b = new[] { baseLength, 0, 0 }; var c = new[] { baseLength+dx, height, 0 }; var d = new[] { 0F+dx, height, 0 }; double expected = baseLength * height; var result = MathUtils.GetConvexQuadrilateralArea(a[0], a[1], a[2], b[0], b[1], b[2], c[0], c[1], c[2], d[0], d[1], d[2]); Assert.AreEqual(expected, result, Epsilon*scale, string.Format("sideA: {0}, height: {1}, dx: {2}", baseLength, height, dx)); } } |
此测试失败,并显示以下消息:预期值74813926.2967871和实际值74813926.2967871之间的差异不大于<1e-09>。侧:8552.44307245707,高:8747.66726454146,深:4721.64729829954。
我的问题是:在仍然使用双精度数字的情况下,有没有办法提高实现的数字精度?
双打有52位小数。以10为基数,大约是15.7位数。你的数字在点的左边有八个数字,所以你只能期望在点的右边有七个正确的数字-这仅仅是由于表示,甚至没有考虑计算产生的累积误差。
所以,答案是:不,没有办法。您必须使用更精确的格式。