C99:复数的虚部能否为负零

标签 c gcc c99 complex-numbers

是否可以在C99复数 float 的虚部存储负零?

我应该如何静态初始化带符号虚部的复常量?

我有一个小例子,但我不明白,为什么 ac 是一样的,为什么 -std=c99 改变了结果。

$ cat zero1.c
int main() {
    float _Complex a;a = 0.0 + (__extension__ 0.0iF);
    float _Complex b;b = 0.0 + (__extension__ -0.0iF);
    float _Complex c;c = -0.0 + (__extension__ 0.0iF);
    float _Complex d;d = -0.0 + (__extension__ -0.0iF);
    printf("a= 0x%016llx\n", *(long long*)(&a));
    printf("b= 0x%016llx\n", *(long long*)(&b));
    printf("c= 0x%016llx\n", *(long long*)(&c));
    printf("d= 0x%016llx\n", *(long long*)(&d));
}

$ gcc-4.5.2 -w -std=c99 zero1.c ; ./a.out
a= 0x0000000000000000
b= 0x0000000000000000
c= 0x0000000000000000
d= 0x0000000080000000

$ gcc-4.5.2 -w zero1.c ; ./a.out
a= 0x0000000000000000
b= 0x8000000000000000
c= 0x0000000000000000
d= 0x8000000080000000

欢迎引用 C99-TC3 和 gcc 手册。

我在 C99 (n1256.pdf) 和 http://www.knosof.co.uk/cbook/ 中都找不到任何相关内容

最佳答案

如果实现符合附件 G 并实现了 _Imaginary 类型,则表达式

b = 0.0 + (__extension__ -0.0iF)

根据 G.5.2 中的规则计算为 (double)0.0 + (double _Imaginary)(-0.0i),并产生 0.0 - 0.0i

如果实现不提供 _Imaginary 类型(这是允许的),或者不符合附件 G(也允许),则此表达式通常被评估为:

  (double _Complex)(0.0 + 0.0i) + (double _complex)(0.0 - 0.0i)
= (double _Complex)((0.0 + 0.0) + (0.0 - 0.0)i)

因为 0.0 - 0.0 在 IEEE-754 默认舍入中是零,所以符号位丢失。

故事的寓意:如果您关心零的符号,请不要在复杂的初始值设定项中使用算术。由于您使用的是 GCC,因此您可以改为这样做:

__real__ c =  0.0f;
__imag__ c = -0.0f;

根据我的经验,这至少可以追溯到 gcc-4.0 左右(可能更远)。

至于为什么该行为是由 -std=c99 触发的,我的最佳猜测如下:您使用的 GCC 版本实现了 _Imaginary 类型不完全符合 C99;当您指定 -std=c99 时,对 _Imaginary 的支持将被关闭,并且您将返回到符合要求的 _Complex 实现,该实现如我所描述的那样工作多于。然而,这只是一个猜测;如果您真的很好奇,我鼓励您提交错误并查看维护人员的意见。实际上,无论如何我都鼓励您提交错误。 始终提交错误

关于C99:复数的虚部能否为负零,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5885096/

相关文章:

c - 是否有任何类别来描述警告?

c - 为什么我不能将 "private"函数声明为静态的,而我根本不能将它放在头文件中?

c++ - 使用 Visual Studios 2012 进行 C++ 编码时,如何自动完成在 IntelliSense 中选择的代码?

c - GCC 编译器优化选项

c - 整数除法的行为是什么?

c - 整个源文件中的头文件重复?

c - main() 在信号处理期间是否暂停?

C++内存对齐问题

c++ - 链接器错误

c - timespec 的存储大小未知