std :: isinf不适用于-ffast-math.如何检查无穷大 [英] std::isinf does not work with -ffast-math. how to check for infinity

查看:110
本文介绍了std :: isinf不适用于-ffast-math.如何检查无穷大的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

示例代码:

#include <iostream>
#include <cmath>
#include <stdint.h>

using namespace std;

static bool my_isnan(double val) {
    union { double f; uint64_t x; } u = { val };
    return (u.x << 1) > 0x7ff0000000000000u;
}

int main() {
    cout << std::isinf(std::log(0.0)) << endl;
    cout << std::isnan(std::sqrt(-1.0)) << endl;
    cout << my_isnan(std::sqrt(-1.0)) << endl;
    cout << __isnan(std::sqrt(-1.0)) << endl;

    return 0;
}

在线编译器.

使用-ffast-math,该代码将显示"0,0,1,1"-不显示,则将显示"1,1,1,1".

With -ffast-math, that code prints "0, 0, 1, 1" -- without, it prints "1, 1, 1, 1".

那是正确的吗?我认为在这些情况下std::isinf/std::isnan仍然可以与-ffast-math一起使用.

Is that correct? I thought that std::isinf/std::isnan should still work with -ffast-math in these cases.

此外,如何使用-ffast-math检查无穷/NaN?您可以看到my_isnan这样做,并且确实有效,但是该解决方案当然取决于体系结构.另外,为什么my_isnan在这里起作用而std::isnan却不起作用? __isnan__isinf呢?他们总是工作吗?

Also, how can I check for infinity/NaN with -ffast-math? You can see the my_isnan doing this, and it actually works, but that solution is of course very architecture dependent. Also, why does my_isnan work here and std::isnan does not? What about __isnan and __isinf. Do they always work?

对于-ffast-mathstd::sqrt(-1.0)std::log(0.0)的结果是什么.它会变得不确定,还是应该是NaN/-Inf?

With -ffast-math, what is the result of std::sqrt(-1.0) and std::log(0.0). Does it become undefined, or should it be NaN / -Inf?

相关讨论:(GCC)[错误libstdc ++/50724]新功能:isnan损坏由-ffinite-math-only在g ++中(Mozilla)错误416287-性能isNaN的改进机会

推荐答案

请注意,-ffast-math可能会使编译器忽略/违反IEEE规范,请参见

Note that -ffast-math may make the compiler ignore/violate IEEE specifications, see http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Optimize-Options.html#Optimize-Options :

除了-Ofast之外,此选项没有由任何-O选项打开,因为它 可能导致依赖于精确的程序的错误输出 IEEE或ISO数学功能的规则/规范的实现. 但是,对于不需要的程序,它可能会产生更快的代码 这些规范的保证.

This option is not turned on by any -O option besides -Ofast since it can result in incorrect output for programs that depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.

因此,使用-ffast-math不能保证在应有的位置看到无穷大.

Thus, using -ffast-math you are not guaranteed to see infinity where you should.

尤其是-ffast-math打开-ffinite-math-only,请参见 http://gcc.gnu.org/wiki/FloatingPointMath 的意思是(来自

In particular, -ffast-math turns on -ffinite-math-only, see http://gcc.gnu.org/wiki/FloatingPointMath which means (from http://gcc.gnu.org/onlinedocs/gcc-4.8.2/gcc/Optimize-Options.html#Optimize-Options )

[...]浮点运算的优化,假定参数和结果不是NaN或+ -Infs

[...] optimizations for floating-point arithmetic that assume that arguments and results are not NaNs or +-Infs

这意味着,通过启用-ffast-math,您可以向编译器保证代码将永远不会使用无穷大或NaN,这反过来又允许编译器通过例如替换对isinf的任何调用来优化代码.或isnan乘以常量false(并从那里进一步优化).如果您违背了对编译器的承诺,则不需要编译器来创建正确的程序.

This means, by enabling the -ffast-math you make a promise to the compiler that your code will never use infinity or NaN, which in turn allows the compiler to optimize the code by, e.g., replacing any calls to isinf or isnan by the constant false (and further optimize from there). If you break your promise to the compiler, the compiler is not required to create correct programs.

因此,答案很简单,如果您的代码可能具有无限性或NaN(使用isinfisnan的事实强烈暗示),则您无法启用-ffast-math,否则可能会得到错误的代码

Thus the answer quite simple, if your code may have infinities or NaN (which is strongly implied by the fact that you use isinf and isnan), you cannot enable -ffast-math as else you might get incorrect code.

您的my_isnan实现可以工作(在某些系统上),因为它直接检查浮点数的二进制表示形式.当然,处理器仍可能进行(某些)实际计算(取决于编译器所做的优化),因此实际的NaN可能会出现在内存中,您可以检查其二进制表示形式,但是如上所述,std::isnan可能已经替换为常量false.同样可能发生的情况是,编译器用某些甚至不会为输入-1生成NaN的版本替换sqrt.为了查看您的编译器进行了哪些优化,请编译为汇编器并查看该代码.

Your implementation of my_isnan works (on some systems) because it directly checks the binary representation of the floating point number. Of course, the processor still might do (some) actual calculations (depending on which optimizations the compiler does), and thus actual NaNs might appear in memory and you can check their binary representation, but as explained above, std::isnan might have been replaced by the constant false. It might equally well happen that the compiler replaces, e.g., sqrt, by some version that doesn't even produce a NaN for input -1. In order to see which optimisations your compiler does, compile to assembler and look at that code.

要进行类比(并非完全无关),如果您告诉编译器您的代码是C ++,则不能指望它正确地编译C代码,反之亦然(例如,有一些实际示例,例如可以编码为在每种语言中进行编译时,在C和C ++中都有效的代码会产生不同的行为?).

To make a (not completely unrelated) analogy, if you're telling your compiler your code is in C++ you can not expect it to compile C code correctly and vice-versa (there are actual examples for this, e.g. Can code that is valid in both C and C++ produce different behavior when compiled in each language? ).

启用-ffast-math并使用my_isnan是个坏主意,因为这会使所有事情都非常依赖于计算机和编译器,您不知道编译器总体上会进行哪些优化,因此可能存在其他与之相关的隐藏问题您正在使用非有限数学的事实,但否则告诉编译器.

It is a bad idea to enable -ffast-math and use my_isnan because this will make everything very machine- and compiler-dependent you don't know what optimizations the compiler does overall, so there might be other hidden problems related to the fact that you are using non-finite maths but tell the compiler otherwise.

一个简单的解决方法是使用-ffast-math -fno-finite-math-only,它仍然会提供一些优化.

A simple fix is to use -ffast-math -fno-finite-math-only which would still give some optimizations.

也可能是您的代码看起来像这样:

It also might be that your code looks something like this:

  1. 过滤掉所有无穷和NaNs
  2. 对过滤后的值进行一些有限的数学运算(这是指保证永远不会产生无限数或NaN的数学运算,必须非常非常仔细地进行检查)

在这种情况下,您可以拆分代码,并使用优化#pragma__attribute__分别为给定的代码段打开和关闭-ffast-math(分别为-ffinite-math-only-fno-finite-math-only)(但是,我记得与此相关的某些版本的GCC会遇到一些麻烦),或者只是将您的代码拆分为单独的文件并使用不同的标志进行编译.当然,如果您可以隔离可能出现无限性和NaN的零件,那么这在更常规的设置中也适用.如果您无法隔离这些部分,则说明您无法将此代码使用-ffinite-math-only.

In this case, you could split up your code and either use optimize #pragma or __attribute__ to turn -ffast-math (respectively -ffinite-math-only and -fno-finite-math-only) on and off selectively for the given pieces of code (however, I remember there being some trouble with some version of GCC related to this) or just split your code into separate files and compile them with different flags. Of course, this also works in more general settings if you can isolate the parts where infinities and NaNs might occur. If you can not isolate these parts, this is a strong indication that you can not use -ffinite-math-only for this code.

最后,重要的是要了解-ffast-math并不是无害的优化,它只会使您的程序更快.它不仅会影响代码的性能,而且还会影响其正确性(如果我记得正确的话,那么这不仅是围绕浮点数的所有问题,而且

Finally, it's important to understand that -ffast-math is not a harmless optimization that simply makes your program faster. It does not only affect the performance of your code but also its correctness (and this on top of all the issues surrounding floating point numbers already, if I remember right William Kahan has a collection of horror stories on his homepage, see also What every programmer should know about floating point arithmetic). In short, you might get faster code, but also wrong or unexpected results (see below for an example). Hence, you should only use such optimizations when you really know what you are doing and you have made absolutely sure, that either

  1. 优化不会影响该特定代码的正确性,或者
  2. 优化引入的错误对代码并不重要.

程序代码实际上可以根据是否使用此优化而有很大不同.尤其是,启用诸如-ffast-math之类的优化时,它的行为可能不正确(或至少与您的预期非常相悖).以以下程序为例:

Program code can actually behave quite differently depending on whether this optimization is used or not. In particular it can behave wrong (or at least very contrary to your expectations) when optimizations such as -ffast-math are enabled. Take the following program for example:

#include <iostream>
#include <limits>

int main() {
  double d = 1.0;
  double max = std::numeric_limits<double>::max();
  d /= max;
  d *= max;
  std::cout << d << std::endl;
  return 0;
}

在没有任何优化标志的情况下进行编译时将产生预期的输出1,但是使用-ffast-math时,它将输出0.

will produce output 1 as expected when compiled without any optimization flag, but using -ffast-math, it will output 0.

这篇关于std :: isinf不适用于-ffast-math.如何检查无穷大的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆