これが私のコードです:
_int f(double x)
{
return isnan(x);
}
_
_#include <cmath>
_の場合、このアセンブリを取得します。
_xorl %eax, %eax
ucomisd %xmm0, %xmm0
setp %al
_
これはかなり賢い方法です。 comisd xとそれ自体の比較が順序付けられていない場合、つまりxがNANの場合、パリティフラグを設定します。次に setp は、パリティフラグを結果にコピーします(1バイトのみ、したがって、最初に_%eax
_をクリアします)。
しかし、私が_#include <math.h>
_の場合、このアセンブリを取得します。
_jmp __isnan
_
現在、コードはインラインではなく、___isnan
_関数は確かにucomisd
命令よりも高速ではないため、何のメリットもなくジャンプが発生しました。コードをCとしてコンパイルすると、同じことがわかります。
ここで、isnan()
呼び出しを__builtin_isnan()
に変更すると、どのヘッダーを含めるかに関係なく、単純なucomisd
命令命令を取得し、Cでも機能します。同様に、私が_return x != x
_だけの場合。
だから私の質問は、なぜC _<math.h>
_ヘッダーはC++ _<cmath>
_ヘッダーよりも効率の悪いisnan()
の実装を提供するのですか?人々は本当に__builtin_isnan()
を使用することを期待されていますか?もしそうなら、なぜですか?
_-O2
_および_-O3
_最適化を使用してx86-64でGCC4.7.2および4.9.0をテストしました。
Gcc4.9に同梱されているlibstdc ++の<cmath>
を見ると、次のようになります。
constexpr bool
isnan(double __x)
{ return __builtin_isnan(__x); }
constexpr
関数は積極的にインライン化することができ、もちろん、関数は作業を__builtin_isnan
に委任するだけです。
<math.h>
ヘッダーは__builtin_isnan
を使用せず、ここに貼り付けるのに少し長い__isnan
実装を使用しますが、私のマシン™ではmath.h
の430行目です。 C99標準ではisnan
et al(C99標準のセクション7.12)にマクロを使用する必要があるため、「関数」は次のように定義されます。
#define isnan(x) (sizeof (x) == sizeof (float) ? __isnanf (x) \
: sizeof (x) == sizeof (double) ? __isnan (x) \
: __isnanl (x))
ただし、__builtin_isnan
の代わりに__isnan
を使用できない理由は見当たらないので、見落としだと思います。 Marc Glisseがコメントで指摘しているように、isinf
の代わりにisnan
を使用した同様の問題については、 関連するバグレポート があります。