我刚走过来,决定尝试一下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()将其变为正数的原因。但奇怪的是它适用于另一种情况,这很奇怪......
求解二次方程并不像大多数人想象的那么简单。
解决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;
给定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中有点生疏,但这应该接近正确的语法。
二次公式是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。
虽然我不认识阿达,但我看到了以下可以优化的事情:
IF
instructiuon的第一个分支,你已经知道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中有一个。对我来说,这个问题与数字算法有关,而与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文章指出的那样,这种实现现在可能已经过时了