负整数零

时间:2019-06-05 10:18:19

标签: python floating-point int

为什么Python可以在float中表示负零,而不能在int中表示负零?

更具体地说:

a = 0.0
print(a)
# 0.0

b = -a
print(b)
# -0.0

但是:

a = 0
print(a)
# 0

b = -a
print(b)
# 0

(我知道这里negative zero in python的关于负浮点零的讨论,但是int并没有在那里真正讨论)。

1 个答案:

答案 0 :(得分:4)

从历史上看,存在可以同时表示-0和+0的整数格式。 符号和大小一个补码都可以表示-0和+0。事实证明,这些方法比 two的补语有用,后者在今天很受欢迎,并且无处不在。

Two的补码具有一些数值特性,使其在硬件中更易于实现,而具有两个零的值则对程序员造成了麻烦。 (我听说过这样的错误,例如帐户余额为-0而不是+0,导致某个人本不应该收到帐单。)

浮点使用符号和大小,因此它可以表示−0和+0。由于浮点数的性质,二进制补码的算术属性对浮点数实现的帮助不大,并且具有两个零的值使程序员在某些情况下可以使用一些额外的信息。

因此,整数和浮点格式的选择是出于实用程序的考虑,而不是数学上的必要性。

看整数运算

让我们考虑在计算机硬件中使用四位来研究一些整数运算。本质上,我们要做的第一件事是实现无符号二进制算术,因此我们设计了一些逻辑门来构成加法器和其他算术单元。因此,加法器的输入0101和0011产生输出1000。

接下来,我们要处理负数。在写作中,我们通过在前面加一个符号来处理负数,因此我们的第一个想法可能是对位进行相同的操作:在前面使用一位表示负数。现在我们有了一个符号和幅度表示。 0001表示+1,而1001表示-1。 0010表示+2,而1010表示-2。 0111代表+7,1111代表-7。并且,当然,0000表示+0,而1000表示-0。这是一个想法,然后我们必须执行它。我们已经有一个加法器,如果将其加到0010(2)和0011(3),它会正确输出0101(5)。但是,如果我们将其送入0011(3)和1001(-1),则输出1100(-4)。因此,我们必须对其进行修改。好吧,还算不错,我们有一个无符号二进制的减法单元,所以我们可以看一下第一位,如果我们要加上一个负数,我们要减去而不是加。这适用于某些操作;对于0011和1001,观察第二个操作数上的前导1并将011和001馈入减法单元,将得出010(2),这是正确的。但是,如果我们有0010和1011,则将010和011馈入减法单元可能会产生一些错误指示(它最初是为无符号二进制设计的),或者可能会“包装”并产生111(因为这样的包装以及“借用”输出”位,使减法单元作为用于减去较宽数字的设计的一部分工作。无论哪种方式,这对于我们的签名号码都是错误的。我们希望0010(2)加1011(−3)的输出为1001(−1)。因此,我们必须设计新的算术单元来处理此问题。也许,当增加数量的混合符号时,他们找出哪个值较大,从较大的值中减去较小的值,然后应用较大的符号位。无论如何,我们都需要做大量的工作来设计加法和减法单元。

另一个建议是,使数字为负,将每一位取反。这就是所谓的补语。这很容易理解并且符合否定的概念,只需否定一切即可。让我们考虑一下它如何影响我们的算术单位。对于+3或-3与+2或-2的组合,我们希望得到以下结果:0011(3)+ 0010(2)= 0101(5),0011(3)+ 1101(-2)= 0001( 1),1100(-3)+ 0010(2)= 1110(-1)和1100(-3)+ 1101(-2)= 1010(-5)。经过检查,有一种简单的方法可以使我们的二进制加法器适应这一要求:对所有四个位进行加法,就好像它们是无符号二进制一样;如果前导位有进位,则将其加回到低位。在无符号的无符号二进制0011 + 0010 = 0101中,因此最终输出为0101。带进位的0011 + 1101 = 0000,因此最终结果为0001。1100 + 0010 = 1110(无进位),因此最终结果为1110 1100 + 1101 = 1001(带进位),因此最终结果为1010。

这很好。我们的补码加法器比符号加法器简单。它不需要比较幅度,也不需要进行减法处理负数。我们可以使其更便宜并获得更多利润。

然后有人想到了两个补码的想法。从概念上讲,我们将从2 n 中减去该数字,而不是反转每一位,其中 n 是位数。因此10000-0001 = 1111表示-1,1110是-2,1101是-3,依此类推。这对我们的加法器有什么作用?

在无符号二进制中,0010(2)+ 1101(13)= 1111(15)。用两个补数表示,即0010(2)+ 1101(−3)= 1111(−1)。这些位是相同的!实际上,这适用于所有两个补码;添加无符号数字的位模式会产生与添加两个补码数字相同的结果。 我们可以对无符号二进制和两个补码使用完全相同的逻辑门。太好了,请该员工加薪。这就是现代硬件所做的;相同的算术单位用于添加或减去两个补码数字,以及用于添加或减去无符号数字。

这是为什么两个以补数表示负整数而胜出的原因的很大一部分。这样可以使计算机更简单,更容易,更便宜,更快速,更高效。

(无符号加法和二进制补码加法之间有区别:如何检测溢出。在无符号加法中,如果高位进位,则发生溢出。在二进制补码加法中,如果存在高位,则发生溢出加法器单元通常通过以一种形式或另一种形式报告两种指示来处理这一点,如果需要,该信息将在以后的说明中进行测试;这不会影响添加本身。)