使用pow时如何避免浮点异常?

时间:2018-01-24 14:34:18

标签: c floating-point numerical floating-point-exceptions

我使用的C库在两个pow

上使用double函数
double a = pow(b, c)

目前,我有b = 0.62c = 1504,这意味着a应该接近0(3.6e-312)。

但我有一个浮点异常。如何避免它并直接返回0?我们能预料到这种情况吗?

我使用Debian 9,64位,我用gcc 6.3编译。该库是ccmaes,这是有问题的一行:

https://github.com/CMA-ES/c-cmaes/blob/eda8268ee4c8c9fbe4d2489555ae08f8a8c949b5/src/cmaes.c#L893

我使用了gdb,因此浮点异常不是来自除法(t-> chiN = 2.74)

如果我尝试重现它,使用FPE发生时的值,我没有问题(编译选项:-fopenmp -O3 -DNDEBUG -fPIC -Wall -Wextra -Wno-long-long -Wconversion -o,like图书馆)

#include <math.h>
#include <stdio.h>

int main() {
    double psxps = 5.6107247793270769;
    double cs = 0.37564049253818982;
    int gen = 752;
    double chiN = 2.7421432615656891;
    int N =8;
    double foo =  sqrt(psxps) / sqrt(1. - pow(1.-cs, 2*gen)) / chiN 
      < 1.4 + 2./(N+1);
    printf("%lf\n",foo);
}

结果:1​​.00000000000

1 个答案:

答案 0 :(得分:1)

至少在概念上,pow(b, c)可被视为exp(c * ln(b))实施。

因此,拦截潜在数字问题的一种方法是使用

自己计算概念pow的第一部分
double i = ln(b);

如果c * i足够小(阈值将是您平台上使用的浮点方案的函数),那么您可以使用C标准库函数继续评估pow

使用exp(c * i)自己完成这项工作可能是不明智的,因为标准的pow函数可能会有各种各样的技巧,以获得精确到{{1}的结果}}