Ada 中的二次方程

发布于 2024-10-08 20:06:42 字数 505 浏览 5 评论 0原文

我刚刚过来并决定尝试一些艾达。 缺点是语法和函数与 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() 将它们变成正数。但奇怪的是,它对于另一种情况却非常有效,这很奇怪......

I just came around and decided to try some Ada.
The downside is that the syntax and function strays quite away from C++.
So I had to like cram various stuff to get this thing to work.

My question is if there are some better way to do this calculation that what I have done here

   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;

I had some problem with negative numbers, that's why I did a IF statement and used ABS() to turn those into positive. But the weird thing is that it works perfectly for the other case, which is strange...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

眼中杀气 2024-10-15 20:06:43

二次公式为 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的符号为负,则有复数根;按照您的意愿处理它们。

如果 b 恰好为负,则用 +abs ( c ) 替换 - c 会产生垃圾。

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

The quadratic formula is x = ( -b +/- sqrt ( b ** 2 - 4*a*c ) ) / ( 2 * a )

I'm guessing a is 1.

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

Calculate d = ( b ** 2 ) * 0.25 - c then check its sign.

If the sign of d is negative you have complex roots; handle them as you wish.

Replacing - c with + abs ( c ) if b happens to be negative will give you rubbish.

Usually multiplying by 0.5 or 0.25 is better than dividing by 2.0 or 4.0.

白芷 2024-10-15 20:06:43

虽然我不了解 Ada,但我看到以下可以优化的内容:

  1. IF 指令的第一个分支中,您已经知道 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 中有的话)。

Though I don't know Ada, I see following things that can be optimized:

  1. In the first branch of the IF instructiuon you already know that B is negative. So you can say B := -B instead of B := ABS(B). Or better: just use -B where you used B in the first branch.
  2. You are using the subexpression B/2.0 four times. It could be more efficient (and also more clear) to assign B/2.0 to an auxilary variable B_2 (or assign it to B again if you don't want to spend another variable) and use it instead.
    Also the sqrt is calculated twice. Assigning it to an auxilariy variable saves runtime (and makes it explicite for the reader that exactly the same subexpresion is used twice).
  3. Than it would probably be faster to use B_2*B_2 instead of **2.0; even better would be to use a dedicated square function, if there is one in Ada.
对你而言 2024-10-15 20:06:43

对我来说,这个问题更多地与数值算法相关,而不是与 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 文章指出的那样,这种实现对于大多数平台来说可能已经过时了

To me, the question is more related to numeric algorithm than to Ada language.
As always with numeric computing, one must often (if not -always-) refer to reference/academic papers.

These kinda questions always reminds me of this :
https://en.wikipedia.org/wiki/Fast_inverse_square_root

You can only find the following tricks if you "do the maths" or find some paper that adresses your issue.

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: as the wikiepdia article points out, this implementation is probably obsolete for most platforms now

泪是无色的血 2024-10-15 20:06:42

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

求解 ax^2 + bx + c = 0 的标准公式是,

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

但是当 4 ac << 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 / a 和 x2 = 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;

Solving quadratic equations is not as simple as most people think.

The standard formula for solving a x^2 + b x + c = 0 is

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

but when 4 a c << b^2, computing x1 involves subtracting close numbers, and makes you lose accuracy, so you use the following instead

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

which yields a better x1, but whose x2 has the same problem as x1 had above.

The correct way to compute the roots is therefore

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

and use x1 = q / a and x2 = c / q, which I find very efficient. If you want to handle the case when delta is negative, or complex coefficients, then you must use complex arithmetic (which is quite tricky to get right too).

Edit: With Ada code:

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;
走走停停 2024-10-15 20:06:42

给定 ax2 + bx + c = 0 二次公式给出 x = (-b +/- sqrt(b2-4ac) ) / 2a 的解。判别式 d = b2-4ac 对于实值根为正值,对于具有非零虚部(即非实复数)的根为负值,并且当根为一个双根。

因此,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 有点生疏,但这应该接近正确的语法。

Given ax2 + bx + c = 0 the quadradic formula gives solutions for x = (-b +/- sqrt(b2-4ac) ) / 2a. The discriminant d = b2-4ac will be positive for real valued roots, negative for roots with a non-zero imaginary component (i.e. a non-real complex number) and will be 0 when the root is a double root.

So, the Ada code for this would be:

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;

Note: I'm a bit rusty in Ada, but this should be close to the proper syntax.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文