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

How does std::cout print negative zero in a ones-complement system?

本文关键字:打印 系统 cout std      更新时间:2023-10-16

在one -complement平台上,下面的代码将打印什么?

#include <iostream>
int main() {
    int i = 1, j = -1;
    std::cout << i+j << std::endl;
    return 0;
}

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

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

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

#include <iostream>
int main() {
    std::cout << ~0 << std::endl;
    return 0;
}

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

首先,为了澄清一点,使用按位操作生成一个负零,然后使用结果值是不可移植的。也就是说,在fprintf(也就是std::basic_ostream::operator<<(int))的文档中没有指定int表示中的符号位是否对应于unsigned表示中的填充位或实际值位。

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

#include <iostream>
int main() {
    std::cout << ~0 << std::endl;
    return 0;
}

确实,将n添加到-n 应该得到负零。但是在实际中不会生成-0,因为1的补加法使用了一种称为补减法的技术(第二个参数是第一个参数的补和减)。

(获得有符号浮点零的惯用方法在这里不适用,因为不能将整数除以零)。

查看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平台上)可能会产生不同的结果。

如果我们从补语的理论角度来看。由于零被定义为(+/-)0,因此0将有两个二进制值,如果我们有4位值,则零将是0000(+0)和1111(-0)。因此,如果加法或减法运算中有过零操作,则必须进行修正。

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

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

正如您在Bit操作中看到的,结果是不正确的,只是不完整的结果。在这种情况下,我们必须在值上加上a +1才能得到正确的结果。为了确定+1是否要加,我们必须看一下加进的结果。如果最左边的数字1100是1,那么我们必须在结果上加1才能得到正确的结果。

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

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

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