1

I have this function:

#include <complex.h>
complex double f(complex double x, complex double y) {
  return x*y;
}

I would like to call it with x = inf + i inf and y = i inf and see what the result is. In particular I want to test if the result is an infinity value (as it should be) or if it is NaN + iNaN. The reason for this is to test different C compilers.

How do you do this in C?

Simd
  • 19,447
  • 42
  • 136
  • 271

4 Answers4

2

I'm not 100% sure this is correct since I've never worked with complex numbers in C, but I've tried this snippet:

#include <stdio.h>
#include <math.h>
#include <complex.h>

double complex f(double complex x, double complex y) {
  return x*y;
}

int main(void)
{
    double complex z1 = INFINITY + INFINITY * I;
    double complex z2 = INFINITY + INFINITY * I;
    complex double result = f(z1, z2);
    printf("%f + i%f\n", creal(result), cimag(result));    
}

I used both clang 3.8 (C 11) and GCC 6.1 (C 11) and the result was:

-inf + i-nan

Based on http://en.cppreference.com/w/c/numeric/math/INFINITY.

Apparently the macro INFINITY is not always supported and thus defined. Check the link above for more info.

nbro
  • 15,395
  • 32
  • 113
  • 196
  • Infinity is fine, but gcc has no imaginary numbers, so those z1 and z2 are not what you think they are. They are inf+nan i, though that's still complex infinity and not NaN under C99 rules – Cubbi Feb 08 '17 at 18:35
2

I would add an intermediate check, too:

#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <math.h>

complex double f(complex double x, complex double y) {
  return x*y;
}

int main(void){
  complex double x = INFINITY + INFINITY * I;
  complex double y = 0.0 + INFINITY * I;
  complex double ret;

  printf("x = %g + %g*I\n", creal(x), cimag(x));
  printf("y = %g + %g*I\n", creal(y), cimag(y));

  ret = f(x,y);

  printf("f = %g + %g*I\n", creal(ret), cimag(ret));

  exit(EXIT_SUCCESS);
}

Why?

Result with gcc-4.9.real (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4

x = nan + inf*I
y = nan + inf*I
f = -inf + -nan*I

Result with Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)

x = nan + inf*I
y = nan + inf*I
f = nan + nan*I

A complete and utter failure from the get go.

deamentiaemundi
  • 5,502
  • 2
  • 12
  • 20
1

You can specify what is basically a complex literal using multiplication with the I macro (which also has a _Complex_I alias). A minor example creating such a value is seen below:

#include <math.h>
#include <complex.h>

int main()
{
  complex c = INFINITY * I + INFINITY;
}
cnettel
  • 1,024
  • 5
  • 7
  • What this answer calls "complex literal", in C is a _constant_. In C++ 'The term “literal” generally designates, in this International Standard, those tokens that are called “constants” in ISO C.' C++ footnote 21 – chux - Reinstate Monica Feb 08 '17 at 15:44
1

The function, as written, is fine, the problem is with the way the complex numbers with special values are created and interpreted.

If you just write

double complex z1 = I * INFINITY;
double complex z2 = INFINITY + I * INFINITY;

you may discover that most of the popular compilers today do not support C99's imaginary numbers, and this expression actually multiplies (0,1) by (inf,0) and then adds (inf,0) to the result.

With gcc, I get z1 = (nan, inf), z2 = (nan, inf), f(z1,z2) = (-inf, -nan)

with clang, I get z1 = (nan, inf), z2 = (nan, inf), f(z1,z2) = (-inf, -nan)

with icc, I get z1 = (-nan, inf), z2 = (-nan, inf), f(z1, z2) = (-nan, -nan)

The only compiler that defines I as a pure imaginary number that I have access to is the C compiler from Oracle Studio

with oracle studio, I get z1 = (0, inf), z2 = (inf, inf), f(z1,z2) = (-inf, inf)

Now this is not actually supposed to be a problem because in C, there is only one Complex Infinity, and every complex number whose one component is infinite is considered to be that infinity, even if the other component is NaN. All built-in arithmetic is supposed to honor that: so in my list above, only Intel appears to have a bug here where multiplication of two complex infinities gave a complex nan.

For the lazy compilers, C11 has a macro that saves the day: CMPLX

double complex z1 = CMPLX(0, INFINITY);
double complex z2 = CMPLX(INFINITY, INFINITY);

now,

with gcc, I get z1 = (0, inf), z2 = (inf, inf), f(z1,z2) = (-inf, inf)

Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • Thank you very much. It's a shame there is no obvious way to report an icc bug. – Simd Feb 08 '17 at 21:06
  • Do you recall which version of GCC you used to compile your last example (using `CMPLX`)? I'm getting an undefined symbol error at link time with my version(s) of GCC. – Keith Prussing Nov 19 '19 at 15:22