2014-02-14 34 views
0

我已經實現了一種計算R3中凸四邊形區域的方法。該方法工作正常,但我有小數點後8位的數值精度問題。採取該方法請看:凸四邊形區域實現的數值精度

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)² + (uz*wx - ux*wz)² + (ux*wy - uy*wx)²} 
      * */ 

      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; 
     } 

這是測試:

[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之間的差值不大於< 1E-09>和實際值74813926.2967871。 sideA:8552.44307245707,height:8747.66726454146,dx:4721.64729829954。

我的問題是:有沒有辦法增加我的實現的數值精度,同時仍然使用雙精度數字?

+1

可能值得發佈到http://scicomp.stackexchange.com/或http://codereview.stackexchange.com –

+0

因爲結果將會是規模的大小^ 2,您可以調整容差:'斷言.AreEqual(期望的,結果,Epsilon * scale * scale,...' –

+0

只是好奇,爲什麼使用三個值而不是矢量'struct'? – ja72

回答

2

雙打有52位小數。以十爲底,即大約15.7位。您的數字在點的左側有八位數字,因此您只能期望在點的右側有七位數字是正確的 - 這只是由於表示,甚至沒有考慮計算產生的任何累積錯誤。

所以,答案是:不,沒有辦法。你必須使用更精確的格式。