Python 浮點數的冷知識

2021-09-28 21:25:08 字數 3172 閱讀 3009

它提到的部分問題,讀者們可以先思考下:

若兩個元組相等,即 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 =

>>

> a

# 作為對比:

>>

> b =

>>

> b

如上所示,兩個 nan 鍵值在表示上一模一樣(注意,它們沒有用引號括起來),它們可以共存,而 inf 卻只能歸併成乙個,再次展示出了 nan 的神奇。

好了,兩個很冷的小知識分享完畢,背後的原因都在於 float() 取浮點數時,python 允許了 nan(不是數)的存在,它表示不確切的存在,所以導致了這些奇怪的結果。

最後,我們作下小結:

Python 浮點數的冷知識

讀者們可以先思考下 若兩個元組相等,即 a b 且 a is b,那麼相同索引的元素 如 a 0 b 0 是否必然相等呢?若兩個物件的 hash 結果相等,即 hash a hash b 那麼它們是否必然相等呢?答案當然都為否 不然就不叫冷知識了 大家可以先嘗試回答一下,然後再往下看。思考分割線 好...

Python 浮點數的冷知識

本週的pycoder s weekly上分享了一篇小文章,它裡面提到的冷知識很有意思,我稍作補充,分享給大家。它提到的部分問題,讀者們可以先思考下 答案當然都為否 不然就不叫冷知識了 大家可以先嘗試回答一下,然後再往下看。思考分割線 好了,先來看看第乙個問題。兩個相同的元組 a b,它們有如下的關係...

Python 浮點數的冷知識

本週的pycoder s weekly上分享了一篇小文章,它裡面提到的冷知識很有意思,我稍作補充,分享給大家。它提到的部分問題,讀者們可以先思考下 答案當然都為否 不然就不叫冷知識了 大家可以先嘗試回答一下,然後再往下看。思考分割線 好了,先來看看第乙個問題。兩個相同的元組 a b,它們有如下的關係...