Python中的负零
我在使用Python时遇到了负零的输出;它的产生方式如下:
k = 0.0
print(-k)
输出结果会是 -0.0
。
但是,当我把 -k
和 0.0 比较是否相等时,结果是 True。请问 0.0
和 -0.0
之间有什么区别吗?(我不在乎它们内部的表示方式不同,我只关心它们在程序中的表现。)有没有什么隐藏的陷阱我需要注意的?
7 个回答
在某些情况下,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
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
可以查看一下维基百科上的−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标准并没有这样做。当乘法或除法涉及带符号的零时,通常的符号规则适用于计算结果的符号。
像divmod
和atan2
这样的操作会表现出这种行为。实际上,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被拒绝了!我不确定这是否后来被重新考虑过。
还可以查看每个计算机科学家都应该知道的浮点运算知识。