关于python:Python-浮点数的冷知识

3次阅读

共计 2175 个字符,预计需要花费 6 分钟才能阅读完成。

本周的 PyCoder’s Weekly 上分享了一篇小文章,它外面提到的冷常识很有意思,我稍作补充,分享给大家。

它提到的局部问题,读者们能够先思考下:

  • 若两个元组相等,即 a==b 且 a is b,那么雷同索引的元素(如 a[0]、b[0])是否必然相等?
  • 若两个对象的 hash 后果相等,即 hash(a) == hash(b),那么它们是否必然相等呢?
    答案当然都为否(不然就不叫冷常识了),大家能够先尝试答复一下,而后再往下看。

好了,先来看看第一个问题。两个雷同的元组 a、b,它们有如下的关系:

>>> a = (float('nan'),)
>>> b = a
>>> a   # (nan,)
>>> b   # (nan,)

>>> type(a), type(b)
(<type 'tuple'>, <type 'tuple'>)

>>> a == b
True

>>> a is b  # 即 id(a) == id(b)
True

>>> a[0] == b[0]
False

以上代码表明:a 等于 b(类型、值与 id 都相等),然而它们的对位元素却不相等。

两个元组都只有一个元素(逗号前面没有别的元素,这是单元素的元组的示意办法,即 len(a)==1)。float() 是个内置函数,能够将入参结构成一个浮点数。

为什么会这样呢?先查阅一下文档,这个内置函数的解析规定是:

sign           ::=  "+" | "-"
infinity       ::=  "Infinity" | "inf"
nan            ::=  "nan"
numeric_value  ::=  floatnumber | infinity | nan
numeric_string ::=  [sign] numeric_value

它在解析时,能够解析前后的空格、前缀的加减号(+/-)、浮点数,除此之外,还能够解析两类字符串(不辨别大小写):”Infinity” 或 ”inf”,示意无穷大数;“nan”,示意不是数(not-a-number),确切地说,指的是除了数以外的所有货色。

后面分享的第一个冷常识就跟“nan”无关,作为整体,两个元组相等,然而它们惟一的元素却不相等。之所以会这样,因为“nan”示意除了数以外的货色,它是一个范畴,所以不可比拟。

作为比照,咱们来看看两个“无穷大的浮点数”是什么后果:

>>> a = (float('inf'),)
>>> b = a
>>> a   # (inf,)
>>> b   # (inf,)

>>> a == b  # True
>>> a is b  # True
>>> a[0] == b[0]  # True

留神最初一次比拟,它跟后面的两个元组恰好相反,由此,咱们能够得出结论:两个无穷大的浮点数,数值相等,而两个“不是数的货色”,数值不相等。

化简一下,能够这样看:

>>> a = float('inf')
>>> b = float('inf')
>>> c = float('nan')
>>> d = float('nan')

>>> a == b  # True
>>> c == d  # False

以上就是第一个冷常识的揭秘。接着看第二个:

>>> hash(float('nan')) == hash(float('nan'))
True

后面刚说了两个“不是数的货色”不相等,这里却显示它们的哈希后果相等,这挺违反常理的。

咱们能够推理出一条简略的论断:不相等的两个对象,其哈希后果可能相等。

起因在于,hash(float(‘nan’)) 的后果等于 0,它是个固定值,作比拟时当然就相等了。

其实,对于 hash() 函数,还埋了一个彩蛋:

>>> hash(float('inf'))  # 314159
>>> hash(float('-inf')) # -314159

有没有感觉这个数值很相熟啊?它正是圆周率的前五位 3.14159,去除小数点后的后果。在晚期的 Python 版本中,负无穷大数的哈希后果其实是 -271828,正是取自于自然对数 e。这两个数都是硬编码在 Python 解释器中的,算是某种致敬吧。

因为 float(‘nan’) 的哈希值相等,这通常意味着它们不能够作为字典的不同键值,然而事实却出乎意料:

>>> a = {float('nan'): 1, float('nan'): 2}
>>> a
{nan: 1, nan: 2}

# 作为比照:>>> b = {float('inf'): 1, float('inf'): 2}
>>> b
{inf: 2}

如上所示,两个 nan 键值在示意上截然不同(留神,它们没有用引号括起来),它们能够共存,而 inf 却只能归并成一个,再次展现出了 nan 的神奇。

好了,两个很冷的小常识分享结束,背地的起因都在于 float() 取浮点数时,Python 容许了 nan(不是数)的存在,它示意不确切的存在,所以导致了这些奇怪的后果。

最初,咱们作下小结:

  • 蕴含 float(‘nan’) 的两个元组,当做整体作比拟时,后果相等;两个相等的元组,其对位的元素可能不相等
  • float(‘nan’) 示意一个“不是数”的货色,它自身不是确定值,两个对象作比拟时不相等,然而其哈希后果是固定值,作比拟时相等;可用作字典的键值,而且是不抵触的键值
  • float(‘inf’) 示意无穷大的浮点数,可看作确定的值,两个对象做比拟时相等,其哈希后果也相等;可用作字典的键值,然而会产生抵触
  • float(‘nan’) 的哈希后果为 0,float(‘inf’) 的哈希后果为 314159

以上就是本次分享的所有内容,想要理解更多 python 常识欢送返回公众号:Python 编程学习圈 ,发送“J”即可收费获取,每日干货分享

正文完
 0