fma()
。请注意,在不支持FMA硬件的平台上,fma()
必须使用模拟,这通常非常慢,并且一些模拟已发现存在严重的功能缺陷。a*b+c
,并在最后应用单个舍入。这允许通过两个本机精度浮点数的未评估的两个本机精度浮点数的和来准确计算它们的乘积,而无需在中间计算中使用扩展精度算术:h = a * b
和l = fma(a, b,- h)
其中h+l
表示乘积a*b
确切地。这提供了以下有效计算ab-cd
的方法:/*
diff_of_products() computes a*b-c*d with a maximum error <= 1.5 ulp
Claude-Pierre Jeannerod, Nicolas Louvet, and Jean-Michel Muller,
"Further Analysis of Kahan's Algorithm for the Accurate Computation
of 2x2 Determinants". Mathematics of Computation, Vol. 82, No. 284,
Oct. 2013, pp. 2245-2264
*/
double diff_of_products (double a, double b, double c, double d)
{
double w = d * c;
double e = fma (-d, c, w);
double f = fma (a, b, -w);
return f + e;
}
使用此构建块,可以计算二次方程的实根,前提是判别式为正且计算结果高度准确:
/* compute the real roots of a quadratic equation: ax² + bx + c = 0,
provided the discriminant b²-4ac is positive
*/
void solve_quadratic (double a, double b, double c, double *x0, double *x1)
{
double q = -0.5 * (b + copysign (sqrt (diff_of_products (b, b, 4.0*a, c)), b));
*x0 = q / a;
*x1 = c / q;
}
a
、b
和c
,使得快速且糙略的判别式为正。通过现代 PC,您可以轻松地运行数十亿个测试向量。我使用了 1000 亿个测试用例,并让其运行了几个小时左右。显然,这对于单元测试来说太长了。因此,您可能需要通过让健壮而朴素的方法并行运行来预生成“困难”的案例,并提取那些使用朴素方法产生大误差的案例。 - njuffaa=1,b=-1e5,c=1
。 - njuffa