C99:复数的虚部可以是负零

osg*_*sgx 7 c gcc c99 complex-numbers

是否有可能在C99复数浮点的虚部存储负零?

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

我有一个小例子,但我无法理解,为什么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
Run Code Online (Sandbox Code Playgroud)

欢迎来自C99-TC3和gcc手册的报价.

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

Ste*_*non 3

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

b = 0.0 + (__extension__ -0.0iF)
Run Code Online (Sandbox Code Playgroud)

(double)0.0 + (double _Imaginary)(-0.0i)根据 G.5.2 中的规则进行评估,并产生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)
Run Code Online (Sandbox Code Playgroud)

由于IEEE-754 默认舍入中0.0 - 0.0零,因此符号位会丢失。

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

__real__ c =  0.0f;
__imag__ c = -0.0f;
Run Code Online (Sandbox Code Playgroud)

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

至于为什么该行为是由 触发的-std=c99,我最好的猜测如下:您使用的 GCC 版本实现了一个_Imaginary不完全符合 C99 的类型;当您指定 时-std=c99,对 的支持_Imaginary将关闭,并且您将依赖于_Complex按照我上面描述的方式工作的一致实现。然而,这只是一个猜测;如果您真的很好奇,我鼓励您提交错误并看看维护人员怎么说。事实上,无论如何我都会鼓励您提交错误。 始终提交错误