Ada中的二次方程

问题描述 投票:10回答:5

我刚走过来,决定尝试一下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()将其变为正数的原因。但奇怪的是它适用于另一种情况,这很奇怪......

math ada
5个回答
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;

2
投票

给定ax2 + bx + c = 0,quadradic formula给出x =( - b +/- sqrt(b2-4ac))/ 2a的解。判别式d = b2-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;

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


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会给你垃圾。

通常乘以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计算两次。将其分配给auxilariy变量可以节省运行时间(并使读者明确表示两次使用完全相同的子表达式)。
  3. 使用B_2*B_2代替**2.0可能会更快;更好的是使用专用的方形函数,如果在Ada中有一个。

-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...? 
    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文章指出的那样,这种实现现在可能已经过时了

© www.soinside.com 2019 - 2024. All rights reserved.