使用pow时如何避免浮点异常? [关闭]

Posted

技术标签:

【中文标题】使用pow时如何避免浮点异常? [关闭]【英文标题】:How to avoid floating point exception when using pow? [closed] 【发布时间】:2018-01-24 14:34:18 【问题描述】:

我使用一个 C 库,它在两个 double 值上使用 pow 函数

double a = pow(b, c)

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

但我有一个浮点异常。如何避免,直接返回0?我们可以预见这种情况吗?

我使用 64 位的 Debian 9,并使用 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,比如图书馆)

#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

【问题讨论】:

@machine_1 我猜是“浮点异常”。 请发帖minimal reproducible example。 你确定你的异常是由于这条线吗?当我在家里尝试您的确切示例时,我得到 5.71612e-313。您能否提供有关您用于“pow”的库、您使用的编译器、在什么系统上等的更多详细信息?也许你应该尝试升级一些东西。浮点异常主要是由于除以 0。 这条“有问题的行”包含除法。哪个可以除以零。我不知道您是如何推断出问题出在pow 中的。 如果您采用您在问题中提出的行,请给它您在问题中提出的值并使用您在问题中陈述的编译器对其进行编译 - 它会给您例外吗? 【参考方案1】:

至少在概念上,pow(b, c) 可以被认为是作为exp(c * ln(b)) 实现的。

因此,拦截潜在数值问题的一种方法是自己计算这个概念 pow 的第一部分,使用

double i = ln(b);

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

exp(c * i) 自己完成这项工作可能是不明智的,因为标准的pow 函数很可能有各种技巧来获得比exp(c * ln(b)) 更准确的结果。

【讨论】:

你的意思是ln而不是log吗? @stackptr:哎呀。 @Bathsheba:pow 实现通常使用对数和指数,但更可能使用以二为底(匹配浮点格式的底数)和专门的代码来计算事物它需要,而不是调用实际的expexp2lnlog2。这些例程无法提供良好的pow 所需的精度。 @EricPostpischil:很好,一如既往。我想知道是否仍然可以按照上述方式进行,检查 c * i,如果满足某些标准或其他,调用标准 pow 函数。 c语言中,log为ln(log10为log)***.com/questions/34205208/…

以上是关于使用pow时如何避免浮点异常? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

使用嵌套命令时可以避免打开 DataReader 异常吗?

如何避免关键程序被意外关闭?

如何避免回归模型中的浮点值

更改用户角色时如何避免数据库异常?

在进行添加时如何通过使用 c++ 模板来避免临时对象? [关闭]

尝试打开新的浏览器窗口时如何避免 Javascript 超时异常?