6
votes

Consider the following code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
int main()
{
   complex double aaa = INFINITY + 0*I;
   printf("%.f + %.f*I\n", creal(aaa), cimag(aaa));
   complex double bbb = 1.0/aaa;
   printf("%.f + %.f*I\n", creal(bbb), cimag(bbb));
   return EXIT_SUCCESS;
}

Compiling with gcc -std=gnu99 -lm, I expect that the output is

inf + 0*I

0 + 0*I

which is true on Linux (tested on Scientific Linux 6.8 with gcc 4.4.7, Fedora 23 with gcc 5.3.1, and Ubuntu 14.04.5 with gcc 4.8.4).

However, on OS X (10.11.5 with clang-602.0.53) instead I get

inf + 0*I

nan + nan*I

It is obvious that clang does not conform the C99 standard (see N1256, Sec. G.5.1; strictly speaking, it's merely a recommended practice, not a standard). In fact, clang does not have the macro __STDC_IEC_559_COMPLEX__ defined, which is introduced in Sec. G.1. Does clang purposely make this behavior? UPDATE: after some checks I find several Linux environments that I tested do not have this macro defined either, but the code still works correctly there.

Currently, my workaround for cross-platform support is to check the macro

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
int main()
{
   complex double aaa = INFINITY + 0*I;
   printf("%.f + %.f*I\n", creal(aaa), cimag(aaa));
   complex double bbb = 1.0/aaa;
   #ifndef __STDC_IEC_559_COMPLEX__
   if(isnan(bbb)) 
   { 
      bbb = 0; //or do some trick that has to do with the problem context
   }
   #endif
   printf("%.f + %.f*I\n", creal(bbb), cimag(bbb));

   return EXIT_SUCCESS;
}   

But I'm not sure if it is robust...Any suggestion?

1
By C standard: INFINITY expands to a constant expression of type float representing positive or unsigned infinity, if available; else to a positive constant of type float that overflows at translation time. So it's behavior might not be identical across platforms... - Eugene Sh.
@EugeneSh. 1. In this case INFINITY does expand to positive infinity, as can be checked by the 1st line of output, or in a debugger; 2. Here I write INFINITY simply to provide a MWE. You could have written something overflowing like complex double aaa = 1.0/0.0; without changing the conclusion; 3. It really doesn't make sense if this doesn't work because I've tested that a double counterpart does (replacing all complex double to double, taking away the functions creal and cimag, etc). - Leo Fang
@LeoFang How it's handled mathematically and how printf() represents it may be not quite the same thing. Maybe the best way to determine if the problem really is clang or the architecture is by compiling it on OSX using gcc. - Havenard
This seems to be an LLVM/Clang issue that was fixed in newer versions. LLVM/Clang 3.6.2 (dating after clang-602.0.53) has the intended behavior while LLVM/Clang 3.5.2 has the described behavior. - kdhp
@kdhp, you are right. Before posting I was testing on LLVM 3.6.0 (clang-602.0.53), and I just tested on another machine running OS X 10.10.5 with LLVM 3.7.0 (clang-700.1.81) which gives me the correct result. You may post an answer and I'll accept it. Thanks! - Leo Fang

1 Answers

1
votes

You are using %f instead of %lf for double arguments. It leads to unpredictable behavior, I think.