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

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

浮點(diǎn)運(yùn)算

浮點(diǎn)數(shù)在計(jì)算機(jī)中表達(dá)為二進(jìn)制(binary)小數(shù)。例如:十進(jìn)制小數(shù)

0.125

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

0.001

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

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

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

0.3

或者更進(jìn)一步的,

0.33

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

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

0.0001100110011001100110011001100110011001100110011...

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

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

>>> 0.1
0.1000000000000000055511151231257827021181583404541015625

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

>>> 1 / 10
0.1

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

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

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

更令人愉快的輸出,您可能希望使用字符串格式化生產(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'

認(rèn)識(shí)到這個(gè)幻覺的真相很重要:機(jī)器不能精確表達(dá) 1/10,你可以簡單的截?cái)?顯示 真正的機(jī)器值。 一種幻覺可能招致另一個(gè)。例如,因?yàn)?.1是不完全的1 /?10,0.1和三的值也不能精確0.3,

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

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

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

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

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

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

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

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

用例需要精確十進(jìn)制表示,試著用它實(shí)現(xiàn)十進(jìn)制運(yùn)算適合會(huì)計(jì)應(yīng)用高精度應(yīng)用十進(jìn)制模塊。

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

如果你過渡使用浮點(diǎn)運(yùn)算,你應(yīng)該看一看數(shù)值 Python 包。很多數(shù)學(xué)和統(tǒng)計(jì)的操作包被SciPy項(xiàng)目提供。 Python 提供了工具,可以幫助在那些罕見的情況諸如當(dāng)你真的想知道一個(gè)浮動(dòng)的精確值的時(shí)候。浮動(dòng)。 as_integer_ratio() 方法表達(dá)一個(gè)浮動(dòng)的價(jià)值作為一個(gè)分?jǐn)?shù):

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

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

>>> x == 3537115888337719 / 1125899906842624
True 

浮動(dòng)。hex() 方法表示十六進(jìn)制浮點(diǎn)數(shù)(16),通過你的計(jì)算機(jī)再次給予確切的值存儲(chǔ):

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

這種精確的十六進(jìn)制表示法可以用來精確重建的浮點(diǎn)值:

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

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

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

表達(dá)錯(cuò)誤

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

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

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

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

J ~= 2**N / 10

J 重現(xiàn)時(shí)正是 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 

因?yàn)橛鄶?shù)大于 10 的一半,最好的近似是取上界:

>>> q+1  
7205759403792794  

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

7205759403792794 / 2 ** 56   

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

3602879701896397 / 2 ** 55

要注意因?yàn)槲覀兿蛏仙崛?,它其?shí)比 1/10 稍大一點(diǎn)點(diǎn)。如果我們沒有向上舍入,它會(huì)比 1/10 稍小一點(diǎn)。但是沒辦法讓它 恰好 是 1/10 !

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

>>> 0.1 * 2 ** 55  
3602879701896397.0  

如果我們用 10**355 除這個(gè)小數(shù),會(huì)看到它最大 55 位(截?cái)嗪蟮模┑氖M(jìn)制值: 這表示存儲(chǔ)在計(jì)算機(jī)中的實(shí)際值近似等于十進(jìn)制值 0.100000000000000005551115123125 。而不是顯示完整的十進(jìn)制值,許多語言(包括舊版本的 Python ),結(jié)果為 17 位有效數(shù)字輪:

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

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

>>> 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'