3

In C, is testing if a float is NaN as fast as testing if two floats are equal? That is is isnan() as fast a simple equality test between two floats?

My particular interest is using gcc on a standard modern Intel/AMD platform.

Here is a sample piece of C code.

#include <math.h>
int main(double x)
{
  return isnan(x);
}
Simd
  • 19,447
  • 42
  • 136
  • 271
  • 2
    Depends on the compiler. If it generates a function call, it won't be as fast, but if the compiler inlines it then it should be. – Barmar Nov 25 '15 at 16:51
  • Look at the generated assembly code. And make sure you enable optimization when you compile. – Barmar Nov 25 '15 at 16:51
  • 1
    Related: [Why does GCC implement isnan() more efficiently for C++ than C ?](http://stackoverflow.com/questions/26052640/why-does-gcc-implement-isnan-more-efficiently-for-c-cmath-than-c-math-h) – cadaniluk Nov 25 '15 at 16:52
  • 1
    Depends on your target architecture and libraries. – too honest for this site Nov 25 '15 at 16:52
  • @Olaf Good point. I have tried to clarify. – Simd Nov 25 '15 at 16:55
  • Why don't you try it and see? Write a program that does 1,000,000 `isnan` calls and another that does 1,000,000 equality tests and see which program is faster. – Andy Lester Nov 25 '15 at 17:03
  • @Barmar How exactly do I look at the assembly. I tried `gcc -O3 -S -o my_asm.s -lm test.c` and `objdump -S --disassemble a.out` but it's not pretty to look at. – Simd Nov 25 '15 at 17:06
  • @AndyLester How do I prevent the compiler from optimizing the loop out? – Simd Nov 25 '15 at 17:07
  • @eleanora Access a `volatile` variable in the loop. – Barmar Nov 25 '15 at 17:07
  • Do you want to compare `isnan(x)` with `x == y` where `y = something;` OR compare `isnan(x)` with `x == y` where `y = NaN;`? It sounds like you are asking about the first which is odd as that is not equivalent functionality. – chux - Reinstate Monica Nov 25 '15 at 17:52
  • @chux It is the first. The question is if we should use something other than NaN in our code to represent unknown values. – Simd Nov 25 '15 at 17:58
  • Is this comparison really causing a performance problem in your application? If not, why are you worrying about it? [Premature optimization is the root of all evil](http://c2.com/cgi/wiki?PrematureOptimization) – Barmar Nov 25 '15 at 18:45

3 Answers3

5

Using GCC on x64, math.h's isnan(float) compiles to

jmp __isnanf

Using tail-call optimization, but effectively calling a function. The called function will have to do something equivalent to the code a bit down, at least I don't see any faster way to implement it. That leaves the question how it compares to a comparison unanswered however.

But that doesn't say anything about how fast "testing if a float is NaN" is, because there isn't just the one way to do it. The most direct way,

int isnan2(float x)
{
  return x != x;
}

Is literally the same thing as comparing floats at the C level. But GCC makes this:

xor eax, eax
ucomiss xmm0, xmm0
setp    al
ret

Which is not quite the same thing as comparing two floats, but close, and in fact a bit faster. Testing for equality means the unordered case tested, as it is here, but then the z flag also has to be tested, like this (from gcc again)

xor eax, eax
mov edx, 1
ucomiss xmm0, xmm1
setp    al
cmovne  eax, edx
ret

Bonus: using <cmath> makes isnan compile to the same thing as comparing a float to itself, see the linked question for why.

Godbolt link for convenience

I now see you actually had double, but that doesn't change anything qualitatively.

harold
  • 61,398
  • 6
  • 86
  • 164
  • Thank you for the very nice disassembly. Do you know if `x!=x` is supposed to work in all compilers? – Simd Nov 25 '15 at 19:08
  • 2
    @eleanora no, because not all of them even support NaN. There are platforms that just don't have NaNs (like TI-83+, some DSPs, etc). Also it doesn't work if you use -ffast-math or some of the related options - they break all sorts of things including usually this. – harold Nov 25 '15 at 19:33
1

The question is if we should use something other than NaN in our code to represent unknown values. (OP comment)

Then you should compare isnan(x) with x == some_constant. If that some_constant did not have a value of 0 or NAN, then the compare could simply be a bit compare if using typical FP representation - hard to beat that by much for speed.

Still, NaN is more idiomatic.

Community
  • 1
  • 1
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

No. The equality test is inline so you pay the price of a function call overhead calling isnan(). But equality can't be used w/o IEEE, so ...

Joshua
  • 40,822
  • 8
  • 72
  • 132