python 中的负零

发布于 2024-09-30 16:37:32 字数 257 浏览 4 评论 0原文

我在 python 的输出中遇到了负零;例如,它的创建如下:

k = 0.0
print(-k)

输出将为-0.0

但是,当我将 -k 与 0.0 进行比较时,结果为 True。 0.0-0.0 之间有什么区别吗(我不关心它们可能有不同的内部表示;我只关心它们在程序中的行为。)我应该注意哪些隐藏的陷阱?

I encountered negative zero in output from python; it's created for example as follows:

k = 0.0
print(-k)

The output will be -0.0.

However, when I compare the -k to 0.0 for equality, it yields True. Is there any difference between 0.0 and -0.0 (I don't care that they presumably have different internal representation; I only care about their behavior in a program.) Is there any hidden traps I should be aware of?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

计㈡愣 2024-10-07 16:37:32

查看维基百科中的 −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!我不确定这是不是后来才发现的。

另请参阅每个计算机科学家应该了解的浮点运算知识。

Check out −0 (number) in Wikipedia

Basically IEEE does actually define a negative zero.

And by this definition for all purposes:

-0.0 == +0.0 == 0

I agree with aaronasterling that -0.0 and +0.0 are different objects. Making them equal (equality operator) makes sure that subtle bugs are not introduced in the code.
Think of 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
>>> 

[Edit: More info based on comments]

When I said for all practical purposes, I had chosen the word rather hastily. I meant standard equality comparison.

As the reference says, the IEEE standard defines comparison so that +0 = -0, rather than -0 < +0. Although it would be possible always to ignore the sign of zero, the IEEE standard does not do so. When a multiplication or division involves a signed zero, the usual sign rules apply in computing the sign of the answer.

Operations like divmod and atan2 exhibit this behavior. In fact, atan2 complies with the IEEE definition as does the underlying "C" lib.

>>> 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

One way is to find out through the documentation, if the implementation complies with IEEE behavior . It also seems from the discussion that there are subtle platform variations too.

However this aspect (IEEE definition compliance) has not been respected everywhere. See the rejection of PEP 754 due to disinterest! I am not sure if this was picked up later.

See also What Every Computer Scientist Should Know About Floating-Point Arithmetic.

暗恋未遂 2024-10-07 16:37:32

math.copysign() 对待 -0.0+0.0 不同,除非你在奇怪的平台上运行 Python:

数学。copysign(x, y)
     返回带有符号yx。在支持带符号零的平台上,copysign(1.0, -0.0) 返回 -1.0

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

math.copysign() treats -0.0 and +0.0 differently, unless you are running Python on a weird platform:

math.copysign(x, y)
     Return x with the sign of y. On a platform that supports signed zeros, copysign(1.0, -0.0) returns -1.0.

>>> import math
>>> math.copysign(1, -0.0)
-1.0
>>> math.copysign(1, 0.0)
1.0
似狗非友 2024-10-07 16:37:32

它在 atan2()< /a> 函数(至少在某些实现中)。在我的 Windows 上的 Python 3.1 和 3.2 中(基于底层 C 实现,根据 Python math 模块文档底部):

>>> 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

It makes a difference in the atan2() function (at least, in some implementations). In my Python 3.1 and 3.2 on Windows (which is based on the underlying C implementation, according to the note CPython implementation detail near the bottom of the Python math module documentation):

>>> 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
他是夢罘是命 2024-10-07 16:37:32

是的,0.0 和 -0.0 之间是有区别的(尽管 Python 不允许我重现它:-P)。如果将正数除以 0.0,则会得到正无穷大;如果将相同的数字除以 -0.0,则会得到负无穷大。

但除此之外,这两个值之间没有实际差异。

Yes, there is a difference between 0.0 and -0.0 (though Python won't let me reproduce it :-P). If you divide a positive number by 0.0, you get positive infinity; if you divide that same number by -0.0 you get negative infinity.

Beyond that, though, there is no practical difference between the two values.

豆芽 2024-10-07 16:37:32

如果您担心遇到 -0.0 的情况,只需在方程中添加 + 0. 即可。它不会影响结果,但会强制零点变为正浮点数。

import math

math.atan2(-0.0, 0.0)
Out[2]: -0.0

math.atan2(-0.0, 0.0) + 0.
Out[3]: 0.0

If you are ever concerned about running into a -0.0 condition, just add + 0. to the equation. It does not influence the results but forces the zeros to a positive float.

import math

math.atan2(-0.0, 0.0)
Out[2]: -0.0

math.atan2(-0.0, 0.0) + 0.
Out[3]: 0.0
聆听风音 2024-10-07 16:37:32

相同的值,但不同的数字

>>> Decimal('0').compare(Decimal('-0'))        # Compare value
Decimal('0')                                   # Represents equality

>>> Decimal('0').compare_total(Decimal('-0'))  # Compare using abstract representation
Decimal('1')                                   # Represents a > b

参考:
http://docs.python.org/2/library/decimal .html#decimal.Decimal.compare
http://docs.python.org/2/library/decimal .html#decimal.Decimal.compare_total

Same values, yet different numbers

>>> Decimal('0').compare(Decimal('-0'))        # Compare value
Decimal('0')                                   # Represents equality

>>> Decimal('0').compare_total(Decimal('-0'))  # Compare using abstract representation
Decimal('1')                                   # Represents a > b

Reference :
http://docs.python.org/2/library/decimal.html#decimal.Decimal.compare
http://docs.python.org/2/library/decimal.html#decimal.Decimal.compare_total

め可乐爱微笑 2024-10-07 16:37:32

为了概括或总结其他答案,实践中的差异似乎来自计算在 0 处中断的函数,其中不连续性来自 0 除法。然而,Python 将 0 除法定义为错误。因此,如果使用 python 运算符计算任何内容,您可以简单地
将 -0.0 视为 +0.0,无需担心。相反,如果该函数是由内置函数或用另一种语言(例如 C)编写的库计算的,则 0 除法可能会在该语言中以其他方式定义,并且可能会给出 -0.0 和 0.0 的不同答案。

To generalise or summarise the other answers, the difference in practice seems to come from calculating functions that are discontinued at 0 where the discontinuity is coming from a 0 division. Yet, python defines a 0 division as an error. So if anything is calculated with python operators, you can simply
consider -0.0 as +0.0 and nothing to worry from. On the contrary, if the function is calculated by a built in function or a library that is written in another language, such as C, the 0 division may be defined otherwise in that language and may give different answers for -0.0 and 0.0.

娜些时光,永不杰束 2024-10-07 16:37:32

Python 浮点数是标准浮点数,但某些操作会在更高级别上捕获并引发 ZeroDivisionErrorOverflowError。因此,在纯 Python 中,您看不到正零和负零之间可以说是最显着的区别,即:在标准浮点算术中,您有 1/(−0) = −∞ ≠ ∞ = 1/0。

但是,库可以删除这些捕获,并在默认情况下不受限制地使用浮点运算。这尤其包括 NumPy,它又被许多其他库在幕后使用。这些库可以按原样使用 Python 浮点数,保留零的符号。在这种情况下,负零和正零之间可能会出现明显的差异,例如:

import numpy as np

some_numbers = [ 0.0, -0.0, 1.0, -1.0, np.inf, -np.inf ]
inverse = lambda x: 1/np.float64(x)
print(sorted(some_numbers,key=inverse))
# [-0.0, -1, inf, -inf, 1, 0.0]

在复杂的数值例程中偶尔会出现这种行为的实际需要。例如,当通过复杂的试验和错误寻找函数的最小值时,错误的猜测可能会导致数值上溢或下溢,但只要所得的无穷大带有正确的符号,极小化器就可以继续工作,而无需废话不多说(拒绝猜测)。我在这个答案中给出了详细的示例。

Python floats are standard floating-point numbers, except that certain actions are caught on a higher level and raise ZeroDivisionError or OverflowError. Therefore, in pure Python, you cannot see the arguably most prominent difference between positive and negative zero, namely: In standard floating-point arithmetics, you have 1/(−0) = −∞ ≠ ∞ = 1/0.

However, libraries can remove these catches, and use floating-point arithmetics without restrictions by default. This particularly includes NumPy, which in turn is used by many other libraries under the hood. These libraries can use Python floats as they are, preserving the sign of zero. In this case, clear differences between negative zero and positive zero can arise, for example:

import numpy as np

some_numbers = [ 0.0, -0.0, 1.0, -1.0, np.inf, -np.inf ]
inverse = lambda x: 1/np.float64(x)
print(sorted(some_numbers,key=inverse))
# [-0.0, -1, inf, -inf, 1, 0.0]

The practical need for such a behaviour occasionally arises in complex numerical routines. For example when looking for the minimum of a function with sophisticated trial and error, a bad guess may lead to a numerical over- or underflow, but as long as the resulting infinity comes along with the correct sign, the minimiser can continue to work without further ado (rejecting the guess). I give a detailed example for this in this answer.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文