Python中關(guān)于浮點(diǎn)數(shù)的冷知識(shí)
本周的PyCoder's Weekly 上分享了一篇小文章,它里面提到的冷知識(shí)很有意思,我稍作補(bǔ)充,分享給大家。
它提到的部分問題,讀者們可以先思考下:
- 若兩個(gè)元組相等,即 a==b 且 a is b,那么相同索引的元素(如 a[0] 、b[0])是否必然相等呢?
- 若兩個(gè)對(duì)象的 hash 結(jié)果相等,即 hash(a) == hash(b),那么它們是否必然相等呢?
答案當(dāng)然都為否(不然就不叫冷知識(shí)了),大家可以先嘗試回答一下,然后再往下看。
-----思考分割線-----
好了,先來看看第一個(gè)問題。兩個(gè)相同的元組 a、b,它們有如下的關(guān)系:
>>> 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 都相等),但是它們的對(duì)位元素卻不相等。
兩個(gè)元組都只有一個(gè)元素(逗號(hào)后面沒有別的元素,這是單元素的元組的表示方法,即 len(a)==1 )。float() 是個(gè)內(nèi)置函數(shù),可以將入?yún)?gòu)造成一個(gè)浮點(diǎn)數(shù)。
為什么會(huì)這樣呢?先查閱一下文檔,這個(gè)內(nèi)置函數(shù)的解析規(guī)則是:
sign ::= "+" | "-" infinity ::= "Infinity" | "inf" nan ::= "nan" numeric_value ::= floatnumber | infinity | nan numeric_string ::= [sign] numeric_value
它在解析時(shí),可以解析前后的空格、前綴的加減號(hào)(+/-)、浮點(diǎn)數(shù),除此之外,還可以解析兩類字符串(不區(qū)分大小寫):"Infinity"或"inf",表示無窮大數(shù);“nan”,表示不是數(shù)(not-a-number),確切地說,指的是除了數(shù)以外的所有東西。
前面分享的第一個(gè)冷知識(shí)就跟“nan”有關(guān),作為整體,兩個(gè)元組相等,但是它們唯一的元素卻不相等。之所以會(huì)這樣,因?yàn)椤皀an”表示除了數(shù)以外的東西,它是一個(gè)范圍,所以不可比較。
作為對(duì)比,我們來看看兩個(gè)“無窮大的浮點(diǎn)數(shù)”是什么結(jié)果:
>>> a = (float('inf'),) >>> b = a >>> a # (inf,) >>> b # (inf,) >>> a == b # True >>> a is b # True >>> a[0] == b[0] # True
注意最后一次比較,它跟前面的兩個(gè)元組恰好相反,由此,我們可以得出結(jié)論:兩個(gè)無窮大的浮點(diǎn)數(shù),數(shù)值相等,而兩個(gè)“不是數(shù)的東西”,數(shù)值不相等。
化簡(jiǎn)一下,可以這樣看:
>>> a = float('inf') >>> b = float('inf') >>> c = float('nan') >>> d = float('nan') >>> a == b # True >>> c == d # False
以上就是第一個(gè)冷知識(shí)的揭秘。接著看第二個(gè):
>>> hash(float('nan')) == hash(float('nan')) True
前面剛說了兩個(gè)“不是數(shù)的東西”不相等,這里卻顯示它們的哈希結(jié)果相等,這挺違背常理的。
我們可以推理出一條簡(jiǎn)單的結(jié)論:不相等的兩個(gè)對(duì)象,其哈希結(jié)果可能相等。
原因在于,hash(float('nan')) 的結(jié)果等于 0,它是個(gè)固定值,作比較時(shí)當(dāng)然就相等了。
其實(shí),關(guān)于 hash() 函數(shù),還埋了一個(gè)彩蛋:
>>> hash(float('inf')) # 314159 >>> hash(float('-inf')) # -314159
有沒有覺得這個(gè)數(shù)值很熟悉???它正是圓周率的前五位 3.14159,去除小數(shù)點(diǎn)后的結(jié)果。在早期的 Python 版本中,負(fù)無窮大數(shù)的哈希結(jié)果其實(shí)是 -271828,正是取自于自然對(duì)數(shù) e。這兩個(gè)數(shù)都是硬編碼在 Python 解釋器中的,算是某種致敬吧。
由于 float('nan') 的哈希值相等,這通常意味著它們不可以作為字典的不同鍵值,但是事實(shí)卻出人意料:
>>> a = {float('nan'): 1, float('nan'): 2} >>> a {nan: 1, nan: 2} # 作為對(duì)比: >>> b = {float('inf'): 1, float('inf'): 2} >>> b {inf: 2}
如上所示,兩個(gè) nan 鍵值在表示上一模一樣(注意,它們沒有用引號(hào)括起來),它們可以共存,而 inf 卻只能歸并成一個(gè),再次展示出了 nan 的神奇。
好了,兩個(gè)很冷的小知識(shí)分享完畢,背后的原因都在于 float() 取浮點(diǎn)數(shù)時(shí),Python 允許了 nan(不是數(shù))的存在,它表示不確切的存在,所以導(dǎo)致了這些奇怪的結(jié)果。
最后,我們作下小結(jié):
- 包含 float('nan') 的兩個(gè)元組,當(dāng)做整體作比較時(shí),結(jié)果相等;兩個(gè)相等的元組,其對(duì)位的元素可能不相等
- float('nan') 表示一個(gè)“不是數(shù)”的東西,它本身不是確定值,兩個(gè)對(duì)象作比較時(shí)不相等,但是其哈希結(jié)果是固定值,作比較時(shí)相等;可用作字典的鍵值,而且是不沖突的鍵值
- float('inf') 表示一個(gè)無窮大的浮點(diǎn)數(shù),可看作確定的值,兩個(gè)對(duì)象做比較時(shí)相等,其哈希結(jié)果也相等;可用作字典的鍵值,但是會(huì)產(chǎn)生沖突
- float('nan') 的哈希結(jié)果為 0,float('inf') 的哈希結(jié)果為 314159
參考資料:
https://docs.python.org/3/library/functions.html#float
https://www.pythondoeswhat.com/2019/09/welcome-to-float-zone.html
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- Python判斷字符串是否為字母或者數(shù)字(浮點(diǎn)數(shù))的多種方法
- python讀取浮點(diǎn)數(shù)和讀取文本文件示例
- Python字符串轉(zhuǎn)換成浮點(diǎn)數(shù)函數(shù)分享
- Python兩個(gè)整數(shù)相除得到浮點(diǎn)數(shù)值的方法
- python中實(shí)現(xiàn)精確的浮點(diǎn)數(shù)運(yùn)算詳解
- 關(guān)于Python中浮點(diǎn)數(shù)精度處理的技巧總結(jié)
- python使用正則搜索字符串或文件中的浮點(diǎn)數(shù)代碼實(shí)例
- python中精確輸出JSON浮點(diǎn)數(shù)的方法
- python十進(jìn)制和二進(jìn)制的轉(zhuǎn)換方法(含浮點(diǎn)數(shù))
- Python雙精度浮點(diǎn)數(shù)運(yùn)算并分行顯示操作示例
相關(guān)文章
使用pandas把某一列的字符值轉(zhuǎn)換為數(shù)字的實(shí)例
今天小編就為大家分享一篇使用pandas把某一列的字符值轉(zhuǎn)換為數(shù)字的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01python中使用paramiko模塊并實(shí)現(xiàn)遠(yuǎn)程連接服務(wù)器執(zhí)行上傳下載功能
paramiko是用python語言寫的一個(gè)模塊,遵循SSH2協(xié)議,支持以加密和認(rèn)證的方式,進(jìn)行遠(yuǎn)程服務(wù)器的連接。這篇文章主要介紹了python中使用paramiko模塊并實(shí)現(xiàn)遠(yuǎn)程連接服務(wù)器執(zhí)行上傳下載功能,需要的朋友可以參考下2020-02-02Pycharm主題切換(禁用)導(dǎo)致UI界面顯示異常的解決方案
這篇文章主要介紹了Pycharm主題切換(禁用)導(dǎo)致UI界面顯示異常的原因分析和解決方案,文中通過圖文結(jié)合的方式給大家介紹的非常詳細(xì),需要的朋友可以參考下2024-06-06python ftp 按目錄結(jié)構(gòu)上傳下載的實(shí)現(xiàn)代碼
這篇文章主要介紹了python ftp 按目錄結(jié)構(gòu)上傳下載的實(shí)現(xiàn)代碼,需要的朋友可以參考下2018-09-09淺析Python 抽象工廠模式的優(yōu)缺點(diǎn)
這篇文章主要介紹了Python 抽象工廠模式的優(yōu)缺點(diǎn),文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下2020-07-07Python流行ORM框架sqlalchemy的簡(jiǎn)單使用
這篇文章主要介紹了Python流行ORM框架sqlalchemy的簡(jiǎn)單使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07Python實(shí)現(xiàn)變聲器功能(蘿莉音御姐音)
這篇文章主要介紹了Python實(shí)現(xiàn)變聲器功能(蘿莉音御姐音),本文圖文實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-12-12