如何将无穷大值传递给函数并测试结果

How to pass infinity values to a function and test the result

我有这个功能:

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

我想用 x = inf + i infy = i inf 调用它,看看结果是什么。特别是我想测试结果是无穷大值(应该是)还是 NaN + iNaN。这样做的原因是为了测试不同的C编译器。

How do you do this in C?

我不是 100% 确定这是正确的,因为我从来没有在 C 中使用过复数,但我试过这个片段:

#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));    
}

我同时使用了 clang 3.8 (C 11) 和 GCC 6.1 (C 11),结果是:

-inf + i-nan

基于http://en.cppreference.com/w/c/numeric/math/INFINITY.

显然宏 INFINITY 并不总是被支持和定义。查看上面的 link 了解更多信息。

您可以使用与 I 宏(它也有一个 _Complex_I 别名)的乘法来指定基本上是一个复杂的文字。下面是创建此类值的一个小示例:

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

int main()
{
  complex c = INFINITY * I + INFINITY;
}

我也会添加中间检查:

#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);
}

为什么?

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

结果 Ubuntu clang 版本 3.4-1ubuntu3 (tags/RELEASE_34/final)(基于 LLVM 3.4)

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

从一开始就彻底失败。

所写的函数很好,问题在于创建和解释具有特殊值的复数的方式。

如果你只写

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

你可能会发现现在大多数流行的编译器都不支持C99的imaginary numbers,而这个表达式实际上是将(0,1)乘以(inf,0)然后加上(inf,0)结果。

使用 gcc,我得到 z1 = (nan, inf), z2 = (nan, inf), f(z1,z2) = (-inf, -nan)

用 clang,我得到 z1 = (nan, inf), z2 = (nan, inf), f(z1,z2) = (-inf, -nan)

使用 icc,我得到 z1 = (-nan, inf), z2 = (-nan, inf), f(z1, z2) = (-nan, -nan)

唯一将 I 定义为我有权访问的纯虚数的编译器是来自 Oracle Studio 的 C 编译器

使用 oracle studio,我得到 z1 = (0, inf), z2 = (inf, inf), f(z1,z2) = (-inf, inf)

现在这实际上不应该是一个问题,因为在 C 中,只有一个复数无穷大,每个一个分量为无穷大的复数都被认为是那个无穷大,即使另一个分量是 NaN 也是如此。所有 built-in 算法都是 supposed to honor that:所以在我上面的列表中,只有英特尔似乎有一个错误,其中两个复数无穷大的乘法给出了一个复数 nan。

对于懒惰的编译器,C11 有一个可以挽救一天的宏:CMPLX

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

现在,

使用 gcc,我得到 z1 = (0, inf), z2 = (inf, inf), f(z1,z2) = (-inf, inf)