【问题标题】:How to pass infinity values to a function and test the result如何将无穷大值传递给函数并测试结果
【发布时间】:2017-06-26 06:56:20
【问题描述】:

我有这个功能:

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

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

你如何在 C 中做到这一点?

【问题讨论】:

  • @chrisaycock 谢谢你部分解决了这个问题。但是我需要创建 x = inf + i inf 并测试结果是否为 NaN + iNaN。
  • 我虽然在浮动中设置 0x7FFFFFFF 创建了一个 NaN
  • @Jean-FrançoisFabre 谢谢。我不想创建一个 NaN。我想创建 x = inf + i inf 和 y = i inf 并测试函数的结果是否为 NaN + iNaN。
  • @eleanora 知道了。我已经撤回了。

标签: c c99 complex-numbers


【解决方案1】:

我不能 100% 确定这是正确的,因为我从未在 C 中处理过复数,但我已经尝试过这个 sn-p:

#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 并不总是被支持并因此被定义。查看上面的链接了解更多信息。

【讨论】:

  • 无穷大很好,但是 gcc 没有虚数,所以那些 z1 和 z2 不是你想象的那样。它们是 inf+nan i,尽管在 C99 规则下仍然是复无穷大而不是 NaN
【解决方案2】:

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

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

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

【讨论】:

  • 这个答案称为“复杂文字”,在 C 中是一个常量。在 C++ 中,“在本国际标准中,术语“文字”通常指代那些在 ISO C 中称为“常量”的标记。 C++ 脚注 21
【解决方案3】:

我也会添加一个中间检查:

#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

从一开始就彻底失败。

【讨论】:

  • 这很令人困惑。为什么你会得到 x = nan + inf*I ?
  • @eleanora 我没有最模糊的想法(不查看编译器源代码),您需要询问相应编译器的作者。
  • FWIW: complex double x = CMPLX(DBL_MAX,DBL_MAX)*2; 在我的平台上生成了“x = inf + inf*I;”,与complex double x = INFINITY + INFINITY * I; 具有相同的“x = nan + inf*I”结果
  • @chux 到底是什么平台?
  • 请记住,inf 在 C99 复数数学中很流行:如果实部或虚部是 inf,即使另一部分是 nan,数字也是复数无穷大。也就是说,nan+nan i 是一个错误。
【解决方案4】:

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

如果你只是写

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。所有内置算术都是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)

【讨论】:

  • 非常感谢。遗憾的是没有明显的方法来报告 icc 错误。
  • 您还记得您用于编译上一个示例的 GCC 版本(使用 CMPLX)吗?我的 GCC 版本在链接时出现未定义符号错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多