Python浮點型(float)運算結(jié)果不正確的解決方案
一、問題說明
以前對浮點數(shù)運行沒有沒有太在意。昨天同事要求把百分比結(jié)果保存到文件上,然后就以保存1位小數(shù)的形式給他保存了。
但是今天同事運行時問能不能統(tǒng)一以一位小數(shù)的形式保存,當時覺得很奇怪昨天就是以一位小數(shù)形式存的怎么還會提這種要求呢。
其給回的截圖確實是部分是一位小數(shù)的,但一部分是很長的。查看代碼都統(tǒng)一如下格式:
# 使用round保留三位小數(shù),然后乘以100,最后格式化為帶百分號的字符串 rate=f"{round(x/y,3) * 100}%"
代碼上沒看出什么問題,直接運行確實是有些結(jié)果是一長串的。進行調(diào)試發(fā)現(xiàn)當x為37y為76時即會出現(xiàn)問題,如下圖所示:
進行步驟拆分,發(fā)現(xiàn)round方法沒有問題,問題在浮點數(shù)乘以100上(同時如下圖可以看到也不是所有浮點數(shù)乘都有問題)
二、原因探究
搞不清原因,直到看到這篇文章:https://www.programiz.com/python-programming/numbers
大意是說二進制對很多浮點數(shù)無法準確表示只能用一個近似值代替,而當使用這些以近似值代替的浮點數(shù)進行進算時本質(zhì)上是這些進似值參與了運算,出來的結(jié)果也就是進似值運算后的結(jié)果。
也就是說,一是這不是乘100的問題也不是乘法的問題而是整個浮點數(shù)運算都有問題,二是這不是python的問題是計算機浮點數(shù)存儲的問題像C、Java等其他計算機語言進行運算都會有問題。
可能有人會疑惑:為什么二進制可以表示2不能表示0.2呢?
這是因為數(shù)值和字符串是不一樣的,如果是字符串那么表示2.2點的左右兩邊的2編碼是一樣的就可以了(如ASCII碼:504650),但數(shù)值不是這樣,數(shù)值的整數(shù)部分和小數(shù)部分需要一個統(tǒng)一的表示形式,那就是加權(quán)位計數(shù)法。
整數(shù)部分都要以2的0次方(20)到2的無窮次方(2∞)表示,這沒有問題,只要長度足夠就能表示出所有奇數(shù)和偶數(shù)。2 = 1 * 21 + 0 * 20 = 10
小數(shù)部分都要以2的-1次方(2-1)到2的負無窮次方(2-∞)表示,這就有問題,因為比如2-1...2-∞不管怎么組合都不能完全等于0.2。0.2 = 0 * 2-1 + 0 * 2-2 + 1 * 2-3 ...
三、處理辦法
這情況讓我想起上份工作局方領(lǐng)導的一句話,應該是“可以理解但不能接受”。
原理上二進制無法精確表示一些浮點數(shù)可以理解,但是就這么返回個顯然錯誤的結(jié)果給用戶那是無法接受的。
python提供了Decimal()方法讓浮點運算結(jié)果可以和人平時運算的結(jié)果一樣。(Decimal本質(zhì)應該還是通過加長長度提高精度)
# Decimal傳字符串才能準確表示,所以需要先用str()把round()的結(jié)果轉(zhuǎn)為字符串 rate=f"{Decimal(str(round(x/y,3))) * 100}%" # 其實上邊的結(jié)果出來是48.700%的形式,即三位小數(shù)的形式并不太符合我們保留一位小數(shù)的想法,真正符合想法得下面這樣 # rate=f"{round(Decimal(str(round(x/y,3))) * 100, 1)}%" # 其實我們說了這么多,我們都是建立在決定保留多少位再乘100這個前提下,倘若我們先乘100后決定保留幾位那都不需要用Decimal # rate=f"{round(x/y*100,1)}%"
參考:
https://www.programiz.com/python-programming/numbers
https://docs.python.org/3.7/library/decimal.html
以上就是Python浮點型(float)運算結(jié)果不正確的解決方案的詳細內(nèi)容,更多關(guān)于Python浮點型(float)運算結(jié)果不正確的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python?range函數(shù)生成一系列連續(xù)整數(shù)的內(nèi)部機制解析
這篇文章主要為大家介紹了Python?range函數(shù)生成一系列連續(xù)整數(shù)的內(nèi)部機制解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12數(shù)據(jù)清洗之如何用一行Python代碼去掉文本中的各種符號
我們在處理文本的時候往往需要對標點符號進行處理,下面這篇文章主要給大家介紹了關(guān)于數(shù)據(jù)清洗之如何用一行Python代碼去掉文本中的各種符號的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-11-11python-parser.parse_args()解析參數(shù)問題
這篇文章主要介紹了python-parser.parse_args()解析參數(shù)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08python實現(xiàn)支持目錄FTP上傳下載文件的方法
這篇文章主要介紹了python實現(xiàn)支持目錄FTP上傳下載文件的方法,適用于windows及Linux平臺FTP傳輸文件及文件夾,需要的朋友可以參考下2015-06-06Python游戲開發(fā)實例之graphics實現(xiàn)AI五子棋
五子棋是經(jīng)典的棋牌類游戲,很多人都玩過,那么如何用Python實現(xiàn)五子棋呢,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11