我刚走过来,决定尝试一下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()将其变为正数的原因。但奇怪的是,它适用于另一种情况,这很奇怪......
答案 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 / 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;
答案 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,但我看到了以下可以优化的事情:
IF
指令的第一个分支中,您已经知道B
是否定的。因此,您可以说B := -B
而不是B := ABS(B)
。或者更好:只需使用-B
在第一个分支中使用B
的地方。 B/2.0
四次。如果你不想花费另一个变量,那么将B/2.0
分配给辅助变量B_2
(或再次将其分配给B
可能会更有效(也更清晰)用它代替。sqrt
计算两次。将其分配给auxilariy变量可以节省运行时间(并使读者明确表示两次使用完全相同的子表达式)。 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文章指出的那样,现在大多数平台的实现都可能已经过时了