启用-ffast-math优化时,exp(-1/0.)是否必然等于0?
exp(-1/0.)在-ffast-math下的可靠性与替代实现 先聊聊常规场景:按照IEEE-754标准,下面这段代码的输出必然是0:
#include <iostream> #include <cmath> int main() { std::cout << std::exp(-1/0.) << "\n"; return 0; }
道理很直白:-1/0.0会生成负无穷(-INF),而exp()作用在负无穷上的结果就是0。
但如果开启了-ffast-math优化编译,情况就不一样了——这个选项会让编译器打破IEEE对无穷数的严格规范,你完全没法再依赖中间步骤得到-INF这个结果。
不过从数学本质来看,指数函数对负参数的表现特别稳定:只要参数是小于-1e+3的有限值,exp()的结果都会是0。所以哪怕编译器把负无穷替换成一个足够大的负有限数,最终输出0的结果在g++-5.4里确实稳定,但这种行为真的值得依赖吗?
答案是:最好别赌编译器的“良心”。这里有个虽然不够优雅,但绝对稳妥的实现方案,不用加任何条件判断就能保证除数始终大于0:
#include <iostream> #include <cmath> #include <limits> int main() { double a = 0.; // 实际场景中,这是个非负的极小值,大多时候大于0,但不绝对 double tiny = 1e-50; double b = std::exp(-1/(a+tiny)); std::cout << b << "\n"; return 0; }
关于这里为什么用1e-50而不是std::numeric_limits<double>::epsilon(),其实是有明确考量的:我们真正想要的是,对于所有能让exp(-1/a)合法的a,都满足a + tiny == a。用epsilon的话,既没法精准传达这个意图,甚至可能让计算结果偏离预期,而1e-50这个小量刚好能贴合需求。
内容的提问来源于stack exchange,提问作者leftaroundabout
相关产品推荐
相关产品推荐

