2011-11-19 70 views
18

我是新來的Java,我一直在試圖實現一個算法,以找到立方程的根源。當我計算判別式並嘗試檢查它相對於零下降的位置時,會出現問題。比較一個零對

如果你運行它,並輸入數字「1 - 5月8 -4」時,輸出如下:

1 -5 8 -4 
p=-0.333333, q=0.074074 
disc1=0.001372, disc2=-0.001372 
discriminant=0.000000000000000
Discriminant is greater than zero. 

我知道這個問題的產生是因爲與雙打的計算是不準確的。通常情況下,判別式應該是0,但最終結果是類似於0.000000000000000。

我的問題是,避免這種情況的最好方法是什麼?我應該檢查一下數字是否在零附近的epsilon鄰域之間?還是有更好更精確的方法?

非常感謝您的回答。

import java.util.Scanner; 

class Cubical { 
    public static void main(String[] args) { 
     // Declare the variables. 
     double a, b, c, d, p, q, gamma, discriminant; 

     Scanner userInput = new Scanner(System.in); 
     a = userInput.nextDouble(); 
     b = userInput.nextDouble(); 
     c = userInput.nextDouble();  
     d = userInput.nextDouble(); 

     // Calculate p and q. 
     p = (3*a*c - b*b)/(3*a*a); 
     q = (2*b*b*b)/(27*a*a*a) - (b*c)/(3*a*a) + d/a; 

     // Calculate the discriminant. 
     discriminant = (q/2)*(q/2) + (p/3)*(p/3)*(p/3); 

     // Just to see the values. 
     System.out.printf("p=%f, q=%f\ndisc1=%f, disc2=%f\ndiscriminant=%.20f\n", p, q, (q/2)*(q/2), (p/3)*(p/3)*(p/3), (q/2)*(q/2) + (p/3)*(p/3)*(p/3)); 

     if (discriminant > 0) { 
      System.out.println("Discriminant is greater than zero."); 
     } 
     if (discriminant == 0) { 
      System.out.println("Discriminant is equal to zero."); 
     } 
     if (discriminant < 0) { 
      System.out.println("Discriminant is less than zero."); 
     } 
    } 
} 

回答

16

最簡單的小量檢查

if(Math.abs(value) < ERROR) 

一個更復雜的是成正比的價值

if(Math.abs(value) < ERROR_FACTOR * Math.max(Math.abs(a), Math.abs(b))) 

在你,你可以將特定的情況下:

if (discriminant > ERROR) { 
    System.out.println("Discriminant is greater than zero."); 
} else if (discriminant < -ERROR) { 
    System.out.println("Discriminant is less than zero."); 
} else { 
    System.out.println("Discriminant is equal to zero."); 
} 
+0

@hattenn:對於OP,彼得的第二個建議是要走的路。 –

+0

哪個值更適合ERROR? –

+0

@LunaKong錯誤取決於上下文。它可能是1e-12到1e-3,或者它可能需要別的東西。 –

14

我應該檢查,如果數量下降的 零的埃普西隆鄰里之間?

究竟

+3

+1到了一個字,不合格(不「IFS或但是」)答案相對於直接的問題。 –

4

這裏的解決方案時的輸入值是整數,那就是精確的,儘管它可能不是最實用的。

對於具有有限二進制表示的輸入值(例如,0.125,但不是0.1),它可能也會正常工作。

訣竅:從中間結果中刪除所有分區,並在結尾處僅分一次。這是通過跟蹤所有(部分)分子和分母來完成的。如果判別式應該爲0,那麼它的分子設爲0.只要中間加法的值在彼此的~2^45的幅度內(這通常是這種情況),在這裏沒有舍入誤差。

// Calculate p and q. 
double pn = 3 * a * c - b * b; 
double pd = 3 * a * a; 

double qn1 = 2 * b * b * b; 
double qd1 = 27 * a * a * a; 
double qn2 = b * c; 
double qn3 = qn1 * pd - qn2 * qd1; 
double qd3 = qd1 * pd; 
double qn = qn3 * a + d * qd3; 
double qd = qd3 * a; 

// Calculate the discriminant. 
double dn1 = qn * qn; 
double dd1 = 4 * qd * qd; 
double dn2 = pn * pn * pn; 
double dd2 = 27 * pd * pd * pd; 

double dn = dn1 * dd2 + dn2 * dd1; 
double dd = dd1 * dd2; 
discriminant = dn/dd; 

(只檢查所提供的輸入值,所以告訴我,如果事情是錯的)

+0

我已經從中間結果中刪除了一些分區,現在它效果更好。謝謝你的提醒。 – hattenn