Ada中的二次方程

时间:2010-12-21 20:59:46

标签: math ada

我刚走过来,决定尝试一下Ada。 缺点是语法和功能远离C ++。 所以我不得不喜欢补充各种东西才能使这个东西发挥作用。

我的问题是,如果有更好的方法来做这个计算,我在这里做了

   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()将其变为正数的原因。但奇怪的是,它适用于另一种情况,这很奇怪......

5 个答案:

答案 0 :(得分:19)

求解二次方程并不像大多数人想象的那么简单。

解决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 :(得分:2)

假设ax 2 + bx + c = 0,quadradic formula给出x =( - b +/- sqrt(b 2 -4ac)的解)/ 2a。判别式d = b 2 -4ac对于实值根是正的,对于具有非零虚部的根(即非实数复数)是负的,并且当根是0时将为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;

注意:我在Ada中有点生疏,但这应该接近正确的语法。

答案 2 :(得分:1)

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

我猜a是1。

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

计算d = ( b ** 2 ) * 0.25 - c然后检查其符号。

如果d的符号为负,则表示复杂的根;按照你的意愿处理它们。

- c如果+ abs ( c )恰好是否定为b,则会将{{1}}替换为垃圾。

通常乘以0.5或0.25优于除以2.0或4.0。

答案 3 :(得分:0)

虽然我不认识Ada,但我看到了以下可以优化的事情:

  1. IF指令的第一个分支中,您已经知道B是否定的。因此,您可以说B := -B而不是B := ABS(B)。或者更好:只需使用-B在第一个分支中使用B的地方。
  2. 您正在使用子表达式B/2.0四次。如果你不想花费另一个变量,那么将B/2.0分配给辅助变量B_2(或再次将其分配给B可能会更有效(也更清晰)用它代替。
    此外,sqrt计算两次。将其分配给auxilariy变量可以节省运行时间(并使读者明确表示两次使用完全相同的子表达式)。
  3. 使用B_2*B_2代替**2.0可能会更快;更好的是使用专用的方形函数,如果在Ada中有一个。

答案 4 :(得分:-1)

对我来说,这个问题与数字算法有关,而与Ada语言有关。 与数字计算一样,必须经常(如果不是 - 总是)参考参考/学术论文。

这些问题总让我想起这个问题: https://en.wikipedia.org/wiki/Fast_inverse_square_root

如果你做数学&#34;你只能找到以下技巧。或者找一些可以解决你问题的论文。

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...? 
    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文章指出的那样,现在大多数平台的实现都可能已经过时了