std :: cout如何在一个补码系统中打印负零?

时间:2015-10-15 14:22:37

标签: c++

在一个补充平台上,下面的代码会打印什么?

#include <iostream>

int main() {
    int i = 1, j = -1;

    std::cout << i+j << std::endl;
    return 0;
}

我怀疑它会打印“0”而不是“-0”,但我似乎找不到任何权威的东西。

编辑为了澄清,我对如何打印-0感兴趣,有几个人建议在实践中,使用上述代码执行one-compliment可能不会产生负零

在这些情况下,建议以下实际生成-0:

#include <iostream>

int main() {
    std::cout << ~0 << std::endl;
    return 0;
}

问题仍然存在:这会打印什么?

4 个答案:

答案 0 :(得分:5)

确实将n添加到-n 应该给你一个负零。但是-0的生成在实践中并没有发生,因为1的补码加法使用了一种称为补充减法器的技术(第二个参数补充并从第一个减去)。 / p>

(获得有符号浮点零的惯用方法并不适用于此,因为您无法将整数除以零)。

答案 1 :(得分:5)

首先,为了澄清事情,使用按位运算制作负零,然后使用结果值是不可移植的。也就是说,fprintf(因此,std::basic_ostream::operator<<(int))的文档中没有指定int表示中的符号位是否对应于unsigned或实际表示中的填充位价值位。

作为结论,这是未指明的行为。

#include <iostream>

int main() {
    std::cout << ~0 << std::endl;
    return 0;
}

答案 2 :(得分:5)

通过glibc源代码,我在vfprintf.c中找到了这些行:

532       is_negative = signed_number < 0;                    \
533       number.word = is_negative ? (- signed_number) : signed_number;      \
534                                           \
535       goto LABEL (number);                            \
...
683       if (is_negative)                            \
684         outchar (L_('-'));                            \

因此,条件似乎为signed_number < 0,对于-0将返回false。

正如@Ysc所提到的,文档中没有任何内容给出了打印-0的任何规范,因此libc的不同实现(在one-compliment上)可能产生不同的结果。

答案 3 :(得分:0)

如果我们看一个补语的理论观点。由于零定义为(+/-)0,如果我们有4个Bit值,则0将有两个二进制值,零为0000(+0)和1111(-0)。因此,如果操作,加法或减法操作中有过零操作,则必须进行校正。

因此,例如,如果我们执行以下操作-2+6=4,结果将按如下方式计算:

  1101 (-2)
+ 0110 (6)
------
 1100  (add carry)
======
  0011 (+3)  

正如您在Bit操作中看到的那样,结果不正确,只是结果不完整。在这种情况下,我们必须为该值添加+1以获得正确的结果。要确定是否必须添加+1,我们必须查看添加进位结果。如果最左边的数字 1 100是一个,那么我们必须在结果中添加+1以获得正确的结果。

如果我们看一下你的例子:

  0001 (+1)
+ 1110 (-1)
------
 0000  (add carry)
======
  1111 (-0)  

我们看到结果将是-0,这将是最终结果,因为左侧的进位位为0。