在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 浮點運算
浮點運算
非正式的 Python 簡介
深入流程控制
標準庫概覽
交互式輸入行編輯歷史回溯
輸入和輸出
使用 Python 解釋器
標準庫概覽Ⅱ
錯誤和異常
模塊
數(shù)據(jù)結(jié)構(gòu)
附錄
接下來?
激起你的興趣

浮點運算

浮點數(shù)在計算機中表達為二進制(binary)小數(shù)。例如:十進制小數(shù)

0.125

是 1/10 + 2/100 + 5/1000 的值,同樣二進制小數(shù):

0.001

是 0/2 + 0/4 + 1/8。這兩個數(shù)值相同。唯一的實質(zhì)區(qū)別是第一個寫為十進制小數(shù)記法,第二個是二進制。

遺憾的是,大多數(shù)十進制小數(shù)不能精確的表達二進制小數(shù)。因此,總的來說,我們輸入的十進制浮點數(shù)的實際存儲在機器上是近似二進制浮點數(shù)。

這個問題更早的時候首先在十進制中發(fā)現(xiàn)??紤]小數(shù)形式的 1/3 ,你可以來個十進制的近似值。

0.3

或者更進一步的,

0.33

諸如此類。如果你寫多少位,這個結(jié)果永遠不是精確的 1/3 ,但是可以無限接近 1/3 。

同樣,無論在二進制中寫多少位,十進制數(shù) 0.1 都不能精確表達為二進制小數(shù)。二進制來表達 1/10 是一個無限循環(huán)小數(shù):

0.0001100110011001100110011001100110011001100110011...

在任意無限位數(shù)值中中止,你可以得到一個近似。在今天的大多數(shù)機器上 Python ,一共有 53 位的精度來表示一個浮點數(shù),所以當你輸入十進制的?0.1?的時候,看到是一個二進制的小數(shù).在1?/?10的情況下,二進制分數(shù)為 3602879701896397?/ 2?*?55,接近但不等于1 /?10的真正價值。

許多用戶都沒有意識到近似由于顯示值的方法。Python 只打印十進制小數(shù)以二進制存儲在 機器中的近似值的十進制近似表示。 在大多數(shù)機器上,如果 Python 打印 0.1 的二進制存儲的真正十進制值,應該顯示為這樣

>>> 0.1
0.1000000000000000055511151231257827021181583404541015625

這比大多數(shù)人找到有用的更數(shù)字化,所以 Python 保持數(shù)字可控的數(shù)量顯示一個圓形的值來代替

>>> 1 / 10
0.1

記住,即使打印結(jié)果看起來像 1?/ 10 的精確值,但是實際存儲的值是最近表示二進制的分數(shù)。

有趣的是,有許多不同的小數(shù),共享相同的最近近似的二進制小數(shù)。在數(shù)字 0.1 和 0.1000000000000000,0.1000000000000000055511151231257827021181583404541015625 都由 3602879701896397 / 2 * 55近似。由于所有這些十進制值共享相同的近似。他們中的任何一個可以同時仍然保持不變的 eval 顯示(repr(x))=?=?x。

歷史上,Python 提示符和內(nèi)置的 repr() 功能會選擇一個17位數(shù),0.1000000000000000。從 Python 3.1,Python(在大多數(shù)系統(tǒng)上)現(xiàn)在可以選擇這些最短和簡單的顯示 0.1。 需要注意的是這在二進制浮點數(shù)是非常自然的:它不是 Python 的 bug,也不是你的代碼的 bug。你會看到只要你的硬件支持浮點數(shù)算法,所有的語言都會有這個現(xiàn)象(盡管有些語言可能默認或完全不?顯示?這個差異)。

更令人愉快的輸出,您可能希望使用字符串格式化生產(chǎn)有限數(shù)量的有效位數(shù):

>>> format(math.pi, '.12g')  # give 12 significant digits
'3.14159265359'

>>> format(math.pi, '.2f')   # give 2 digits after the point
'3.14'

>>> repr(math.pi)
'3.141592653589793'

認識到這個幻覺的真相很重要:機器不能精確表達 1/10,你可以簡單的截斷 顯示 真正的機器值。 一種幻覺可能招致另一個。例如,因為0.1是不完全的1 /?10,0.1和三的值也不能精確0.3,

>>> .1 + .1 + .1 == .3
False

同時,由于 0.1 不能接近 1?/?10 的準確值和 0.3 不能接近 53/ 10 的精確值,然后用 round() 功能不能幫助預舍入:

>>> round(.1, 1) + round(.1, 1) + round(.1, 1) == round(.3, 1)
False 

雖然數(shù)字不能接近其預期的精確值,但是 round() 函數(shù)對后四舍五入是有用的,以至于結(jié)果與精確值舍入成為相互比較:

>>> round(.1 + .1 + .1, 10) == round(.3, 10)
True 

浮點數(shù)據(jù)算法產(chǎn)生了很多諸如此類的驚奇。在“表現(xiàn)錯誤”一節(jié)中,這個 “0.1”問題詳細表達了精度問問題。

最后我要說,“沒有簡單的答案”。還是不要過度的敵視浮點數(shù)!Python 浮點 數(shù)操作的錯誤來自于浮點數(shù)硬件,大多數(shù)機器上同類的問題每次計算誤差不超過 2**53 分之一。對于大多數(shù)任務這已經(jīng)足夠讓人滿意了。但是你要在心中記住這不是十 進制算法,每個浮點數(shù)計算可能會帶來一個新的精度錯誤。

問題已經(jīng)存在了,對于大多數(shù)偶發(fā)的浮點數(shù)錯誤,你應該比對你期待的最終顯示結(jié)果是否符合你的期待。 str() 通常夠用了,完全的控制參見字符串語法中 str.format() 方法的格式化方式。

用例需要精確十進制表示,試著用它實現(xiàn)十進制運算適合會計應用高精度應用十進制模塊。

以有理數(shù)為基礎(chǔ)的執(zhí)行算術(shù)分模塊支持另一種準確算術(shù)。(所以像1/3那樣的數(shù)字能更準確的表達)

如果你過渡使用浮點運算,你應該看一看數(shù)值 Python 包。很多數(shù)學和統(tǒng)計的操作包被SciPy項目提供。 Python 提供了工具,可以幫助在那些罕見的情況諸如當你真的想知道一個浮動的精確值的時候。浮動。 as_integer_ratio() 方法表達一個浮動的價值作為一個分數(shù):

>>> x = 3.14159
>>> x.as_integer_ratio()
(3537115888337719, 1125899906842624)

自比是精確的,它可用于無損重建原始值:

>>> x == 3537115888337719 / 1125899906842624
True 

浮動。hex() 方法表示十六進制浮點數(shù)(16),通過你的計算機再次給予確切的值存儲:

>>> x.hex()
'0x1.921f9f01b866ep+1'

這種精確的十六進制表示法可以用來精確重建的浮點值:

>>> x == float.fromhex('0x1.921f9f01b866ep+1')
True 

由于精確的表示是準確的,可靠的移植值在不同版本的 Python 是有用的(平臺獨立性)。與其他語言支持相同的數(shù)據(jù)交換格式(如 Java 和 C99 中)。 另一個有用的工具是 math.fsum() 函數(shù),它有助于減輕損失精度的總和。它跟蹤的“失去的數(shù)字”的值添加到運行總和。那樣可以使整體精度,誤差不積累,從而影響最終的總角度的差異:

>>> sum([0.1] * 10) == 1.0
False
>>> math.fsum([0.1] * 10) == 1.0
True 

表達錯誤

這一節(jié)詳細說明“0.1”示例,教你怎樣自己去精確的分析此類案例。假設(shè)這里 你已經(jīng)對浮點數(shù)表示有基本的了解。

Representation error 提及事實上有些(實際是大多數(shù))十進制小數(shù)不 能精確的表示為二進制小數(shù)。這是 Python (或 Perl,C,C++,Java,F(xiàn)ortran 以及其它很多)語言往往不能按你期待的樣子顯示十進制數(shù)值的根本原因。

這是為什么? 1/10 不能精確的表示為二進制小數(shù)。大多數(shù)今天的機器(2000年十一月)使用 IEEE-754 浮點數(shù)算法,大多數(shù)平臺上 Python 將浮點數(shù)映射為 IEEE-754 “雙精度浮點數(shù)”。754 雙精度包含 53 位精度,所以計算機努力將輸入的 0.1 轉(zhuǎn)為 J/2**N最接近的二進制小數(shù)。 J 是一個 53 位的整數(shù)。改寫:

1 / 10 ~= J / (2**N)

J ~= 2**N / 10

J 重現(xiàn)時正是 53 位(是 >= 2**52 而非 < 2**53 ), N 的最佳值是 56:

>>> 2**52 <= 2**56 // 10 < 2**53  
True  

因此,56 是保持 J 精度的唯一 N 值。 J 最好的近似值是整除的商:

>>> q, r = divmod(2**56, 10)  
>>> r  
6 

因為余數(shù)大于 10 的一半,最好的近似是取上界:

>>> q+1  
7205759403792794  

因此在 754 雙精度中 1/10 最好的近似值是是 2**56 ,或:

7205759403792794 / 2 ** 56   

分裂分子和分母的減少率:

3602879701896397 / 2 ** 55

要注意因為我們向上舍入,它其實比 1/10 稍大一點點。如果我們沒有向上舍入,它會比 1/10 稍小一點。但是沒辦法讓它 恰好 是 1/10 !

所以計算機永遠也不 “知道” 1/10 :它遇到上面這個小數(shù),給出它所能得到的最佳的 754 雙精度實數(shù):

>>> 0.1 * 2 ** 55  
3602879701896397.0  

如果我們用 10**355 除這個小數(shù),會看到它最大 55 位(截斷后的)的十進制值: 這表示存儲在計算機中的實際值近似等于十進制值 0.100000000000000005551115123125 。而不是顯示完整的十進制值,許多語言(包括舊版本的 Python ),結(jié)果為 17 位有效數(shù)字輪:

>>> 3602879701896397 * 10 ** 55 // 2 ** 55
1000000000000000055511151231257827021181583404541015625

分數(shù)模塊和小數(shù)模塊使得這些計算變得簡單:

>>> from decimal import Decimal
>>> from fractions import Fraction

>>> Fraction.from_float(0.1)
Fraction(3602879701896397, 36028797018963968)

>>> (0.1).as_integer_ratio()
(3602879701896397, 36028797018963968)

>>> Decimal.from_float(0.1)
Decimal('0.1000000000000000055511151231257827021181583404541015625')

>>> format(Decimal.from_float(0.1), '.17')
'0.10000000000000001'