I use std::complex<> in my programs, and have to fight with compiler flags and workaround for each new compiler or compiler upgrade. I will try to recount these fights in chronological order:
- Performance measurements showed that a a step involving only computing the square of the absolute value of a field of complex numbers took more time than a preceding FFT for gcc-4.x. Digging into the generated assembler code showed that
std::norm ($|z|^2$) computed the absolute value ($|z|$) in a way avoiding overflow, and then squared the result. This problem could be fixed by the compile flag -ffast-math.
- The intel icc compiler on linux (or linker) compiled
std::arg to a non-opt under certain configurations (link compatibility with a specific gcc-version). The problem resurfaced too often, so std::arg had to be replaced by atan2(imag(),real()). But it was all too easy to forget this when writing new code.
- The type
std::complex uses different call conventions (=ABI) than the build-in C99 complex type, and the built-in Fortran complex type for newer gcc versions.
- The
-ffast-math compile flag interacts with the handling of floating point exceptions in unexpected ways. What happens is that the compiler pulls divisions out of loops, thereby causing division by zero exceptions at runtime. These exceptions would have never happened inside the loop, because the corresponding division didn't take place due to the surrounding logic. That one was really bad, because it was a library that was compiled separately from the program which used the floating point exception handing (using different compile flags) and run into these issues (the corresponding teams were sitting at opposite parts of the world, so this issue really caused bad trouble). This was solved by doing the optimization used by the compiler by hand with more care.
- The library became part of the program and no longer used the
-ffast-math compile flag. After an upgrade to a newer gcc version, performance dropped by a huge factor. I haven't investigated this issue in detail yet, but I fear it is related to C99 Annex G. I have to admit that I'm completely confused by this strange definition of multiplication for complex numbers, and there even seems to exist different versions of this with claims that the other versions are misguided. I hope that the -fcx-limited-range compile flag will solve the issue, because there seems to be another problem related to -ffast-math for this newer gcc version.
- The
-ffast-math compile flag makes the behavior of NaN completely unpredictable for newer versions of gcc (even isnan is affected). The only workaround seems to be to avoid any occurrence of NaN in the program, which defeats the purpose for the existence of NaN.
Now you may ask whether I plan to abandon the built-in complex types and std::complex for these reasons. I will stay with the built-in types, as long as I stay with C++. In case C++ should manage to become completely unusable for scientific computing, I would rather considering to switch to a language that takes more care of the issues relevant to scientific computing.