Python中的负零

65 投票
7 回答
51185 浏览
提问于 2025-04-16 06:28

我在使用Python时遇到了负零的输出;它的产生方式如下:

k = 0.0
print(-k)

输出结果会是 -0.0

但是,当我把 -k 和 0.0 比较是否相等时,结果是 True。请问 0.0-0.0 之间有什么区别吗?(我不在乎它们内部的表示方式不同,我只关心它们在程序中的表现。)有没有什么隐藏的陷阱我需要注意的?

7 个回答

18

在某些情况下,atan2() 这个函数的表现会有所不同。根据我在Windows上使用的Python 3.1和3.2版本(这些版本是基于底层的C语言实现的,具体可以参考Python math模块文档底部的CPython实现细节说明):

>>> import math
>>> math.atan2(0.0, 0.0)
0.0
>>> math.atan2(-0.0, 0.0)
-0.0
>>> math.atan2(0.0, -0.0)
3.141592653589793
>>> math.atan2(-0.0, -0.0)
-3.141592653589793
22

math.copysign() 这个函数会把 -0.0+0.0 当成不同的数来处理,除非你在一些特别的系统上运行 Python:

math.copysign(x, y)
     这个函数会返回 x,但是会把 y 的符号给 x。如果你的系统支持带符号的零,那么 copysign(1.0, -0.0) 会返回 -1.0

>>> import math
>>> math.copysign(1, -0.0)
-1.0
>>> math.copysign(1, 0.0)
1.0
50

可以查看一下维基百科上的−0 (数字)

简单来说,IEEE确实定义了一个负零。

根据这个定义,在所有实际应用中:

-0.0 == +0.0 == 0

我同意aaronasterling的看法,-0.0+0.0是不同的对象。将它们视为相等(使用相等运算符)可以确保代码中不会引入微妙的错误。
想象一下a * b == c * d

>>> a = 3.4
>>> b =4.4
>>> c = -0.0
>>> d = +0.0
>>> a*c
-0.0
>>> b*d
0.0
>>> a*c == b*d
True
>>> 

[编辑:根据评论提供更多信息]

当我说“在所有实际应用中”时,我选择这个词有点草率。我指的是标准的相等比较。

正如参考资料所说,IEEE标准定义了比较方式,使得+0 = -0,而不是-0 < +0。虽然在计算中可以始终忽略零的符号,但IEEE标准并没有这样做。当乘法或除法涉及带符号的零时,通常的符号规则适用于计算结果的符号。

divmodatan2这样的操作会表现出这种行为。实际上,atan2 符合IEEE的定义,底层的“C”库也是如此。

>>> divmod(-0.0,100)
(-0.0, 0.0)
>>> divmod(+0.0,100)
(0.0, 0.0)

>>> math.atan2(0.0, 0.0) == math.atan2(-0.0, 0.0)
True 
>>> math.atan2(0.0, -0.0) == math.atan2(-0.0, -0.0)
False

一种方法是通过文档来查找实现是否符合IEEE的行为。讨论中似乎也提到了一些平台之间的微妙差异。

然而,这个方面(符合IEEE定义)并不是在所有地方都得到尊重。由于缺乏兴趣,PEP 754被拒绝了!我不确定这是否后来被重新考虑过。

还可以查看每个计算机科学家都应该知道的浮点运算知识

撰写回答