2016-05-24 41 views
3

我試圖計算與頂點的三角形如何避免在這個三角形面積計算中的舍入誤差?

{{0,1000000000},{1,0},{0,-1000000000}} 

很容易看出,這個三角形的面積應該是10億的區域,但是當我嘗試使用任何海倫公式來計算在Java中區或鞋帶公式,我得到0的地區。

我很確定這是由於使用double s時的舍入錯誤,但我不確定如何繼續。任何指針?

計劃:

private static double areaShoelace(int[][] v) { 
    return 0.5 * Math.abs(v[0][0]*v[1][1] + v[1][0]*v[2][1] + v[2][0]*v[0][1] + 
      v[1][0]*v[0][1] + v[2][0]*v[1][1] + v[0][0]*v[2][1]); 
} 

private static double areaHeron(double a, double b, double c) { 
    double p = (a + b + c)/2.0d; 
    return Math.sqrt(p * (p - a) * (p - b) * (p - c)); 
} 

private static double length(int[] a, int [] b) { 
    return Math.hypot(a[0] - b[0], a[1] - b[1]); 
} 

public static void main(String[] args) { 
    int[][] tri = new int[][]{{0,1000000000},{1,0},{0,-1000000000}}; 
    System.out.println(areaShoelace(tri)); 
    System.out.println(areaHeron(length(tri[0], tri[1]), length(tri[1],tri[2]), length(tri[0],tri[2]))); 
} 

輸出:

0.0 
0.0 
+0

你看過這個問題:「Java中float和double的包含範圍是什麼?」這可能會對您的問題有所瞭解。 http://stackoverflow.com/questions/1650505/what-is-the-inclusive-range-of-float-and-double-in-java – Alos

+0

即使數字較小,您的'areaShoelace()'仍然爲0。 –

回答

2

這裏實際上有2個不同的錯誤。

在您的shoelace formula實現中,某些標誌不正確(一半應爲負值)。一旦你解決了這個問題,你應該在這種情況下得到正確的答案,但是你應該注意到乘法和加法正在使用整數算法來執行,這可能會導致大數量的溢出。

如果更改這些浮點運算,它也可能是有意義的組他們減少操作的兩個數,併爲破壞性相消的潛力,我會建議

0.5*Math.abs(v[0][0]*(v[1][1] - v[2][1]) + v[1][0]*(v[2][1] - v[0][1]) + 
     v[2][0]*(v[0][1] - v[1][1])) 

數值問題Heron的公式已經完善並由浮點高手威廉卡漢解釋:Miscalculating Area and Angles of a Needle-like Triangle

然而,在這種情況下,即使在此之前,您的問題仍然存在:Math.hypot(1, 1000000000)的結果在數值上等於1000000000(其餘數字會丟失爲浮點舍入),因此在輸入Heron公式時(即使精確計算) ,將給出0.

+0

@Sneftel也提供了豐富的答案,但您的答案指出了代碼中的缺陷。好眼睛! – jimpudar

2

海倫公式不是非常尖或鈍三角形的良好匹配,因爲p(p-x)方面的至少一個從災難遭受消除。

更穩健的方法是計算三角形相對於最長邊的高度,然後使用公式A=0.5*b*h。通過找到最接近第三個頂點的基礎上的位置並測量它到該頂點的距離來計算高度,而不是使用傳統的叉積(其本身會遭受災難性消除)。

1

在java中避免舍入錯誤的一種方法是使用java.math.BigDecimal而不是原始雙精度浮點數或浮點數。