2010-12-21 61 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文章指出,这种实现可能已经过时了现在多数平台