2010-12-21 85 views
9

我剛來,並決定嘗試一些Ada。 缺點是語法和函數離C++很遠。 所以我不得不喜歡塞滿各種東西才能使這件事情起作用。Ada中的二次方程

我的問題是,如果有一些更好的方式來做到這一點的計算是什麼,我在這裏做

IF(B < 0.0) THEN 
     B := ABS(B); 
     X1 := (B/2.0) + Sqrt((B/2.0) ** 2.0 + ABS(C)); 
     X2 := (B/2.0) - Sqrt((B/2.0) ** 2.0 + ABS(C)); 
    ELSE 
     X1 := -(B/2.0) + Sqrt((B/2.0) ** 2.0 - C); 
     X2 := -(B/2.0) - Sqrt((B/2.0) ** 2.0 - C); 
    END IF; 

我遇到了一些問題,負數,這就是爲什麼我做了一個IF語句,並使用ABS()把這些變成積極的。但奇怪的是,它完全適用於其他情況下,這是奇怪...

+1

+1爲SO – ja72 2010-12-22 02:24:41

+1

關於第一個兩行提ADA - 我會避免使用ABS()當你已經知道B是否定的時候。使用B:= - B。即使編譯器很聰明並且可以內聯東西。 – DarenW 2011-01-06 23:21:57

回答

18

求解二次方程並不像大多數人想象的那麼簡單。

解決a x^2 + b x + c = 0的標準公式是

delta = b^2 - 4 a c 
x1 = (-b + sqrt(delta))/(2 a) (*) 
x2 = (-b - sqrt(delta))/(2 a) 

但當4 a c << b^2,計算x1涉及減去密切號碼,使你失去精度,所以你改用以下

delta as above 
x1 = 2 c/(-b - sqrt(delta))  (**) 
x2 = 2 c/(-b + sqrt(delta)) 

其收益率更好的x1,但是其x2與x1具有相同的問題。因此

計算根的正確方法是

q = -0.5 (b + sign(b) sqrt(delta)) 

,並使用x1 = q/ax2 = c/q,我覺得這非常有效。如果您想要處理delta爲負數或復係數的情況,那麼您必須使用複雜的算術(這也很難實現)。

編輯:Ada語言代碼:

DELTA := B * B - 4.0 * A * C; 

IF(B > 0.0) THEN 
    Q := -0.5 * (B + SQRT(DELTA)); 
ELSE 
    Q := -0.5 * (B - SQRT(DELTA)); 
END IF; 

X1 := Q/A; 
X2 := C/Q; 
1

二次公式是x = (-b +/- sqrt (b ** 2 - 4*a*c))/(2 * a)

我猜測是1

所以x = -(b/2) +/- sqrt (((b ** 2)/4) - c)

計算d = (b ** 2) * 0.25 - c然後檢查其符號。

如果d的符號爲負值,則表示複雜的根;如你所願處理它們。

更換- c+ abs (c)如果b碰巧是否定的會給你垃圾。

通常乘以0.5或0.25比除以2.0或4.0更好。

0

雖然我不知道艾達,我看到下面的東西,可以進行優化:

  1. IF的第一支instructiuon你已經知道B爲負。所以你可以說B := -B而不是B := ABS(B)。或者更好:只需使用-B,在第一個分支中使用B
  2. 您正在使用子表達式B/2.0四次。將B/2.0分配給輔助變量B_2(或者如果您不想花費其他變量,則將其重新指定爲B)並將其用於替代,可能會更有效(也更清晰)。
    另外sqrt計算兩次。將它分配給一個輔助變量可以節省運行時間(並且使讀者明白,兩次使用完全相同的子表達式)。
  3. 比使用B_2*B_2代替**2.0可能會更快;如果Ada中有一個函數,更好的辦法是使用專用的方塊函數。
2

鑑於斧 + BX + C = 0的quadradic formula給出的解決方案對於x =(-b +/- SQRT(B -4ac))/ 2a上。判別式d = b -4ac對於實數值根是正的,對於具有非零虛數分量的根(即非實數複數)是負的,並且當根是雙根時將爲0。

所以,這樣做的Ada代碼將是:

D := B ** 2.0 - 4.0 * A * C; 
IF D >= 0.0 THEN 
    X1 := (-B + Sqrt(D))/(2.0 * A); 
    X2 := (-B - Sqrt(D))/(2.0 * A); 
ELSE 
    -- Deal with the fact that the result is a non-real complex number. 
END IF;

注:我在阿達有點生疏,但是這應該是接近正確的語法。

+1

關閉;所有的數字都需要是真實的(第一行4.0,第二行0.0,第三和第四行2.0)。另外,不需要在條件表達式中放置括號。如果D <= 0.0,那麼`。 – 2010-12-22 00:21:35

-1

對我來說,這個問題是不是Ada語言更多的相關數值算法。 與數字計算一樣,必須經常(如果不是) - 參考參考/學術論文。

這些有點問題,總讓我想起的是: https://en.wikipedia.org/wiki/Fast_inverse_square_root

你只能找到下面的技巧,如果你「做數學」,或找一些紙你不會忽略的問題。

float Q_rsqrt(float number) 
{ 
    long i; 
    float x2, y; 
    const float threehalfs = 1.5F; 

    x2 = number * 0.5F; 
    y = number; 
    i = * (long *) &y;      // evil floating point bit level hacking 
    i = 0x5f3759df - (i >> 1);    // what the fuck? 
    y = * (float *) &i; 
    y = y * (threehalfs - (x2 * y * y)); // 1st iteration 
// y = y * (threehalfs - (x2 * y * y)); // 2nd iteration, this can be removed 

    return y; 
} 

PS:作爲wikiepdia文章指出,這種實現可能已經過時了現在多數平臺