鍍金池/ 教程/ Python/ 除法
標(biāo)準(zhǔn)庫 (4)
如何成為 Python 高手
標(biāo)準(zhǔn)庫 (6)
標(biāo)準(zhǔn)庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網(wǎng)站 (5)
文件(1)
練習(xí)
列表(3)
從小工到專家
除法
錯(cuò)誤和異常 (2)
函數(shù)(1)
用 tornado 做網(wǎng)站 (7)
為做網(wǎng)站而準(zhǔn)備
函數(shù)練習(xí)
標(biāo)準(zhǔn)庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網(wǎng)站 (3)
字符串(1)
函數(shù)(2)
寫一個(gè)簡單的程序
將數(shù)據(jù)存入文件
語句(5)
SQLite 數(shù)據(jù)庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網(wǎng)站 (6)
用 tornado 做網(wǎng)站 (2)
自省
語句(4)
錯(cuò)誤和異常 (1)
用 tornado 做網(wǎng)站 (4)
集合(2)
列表(1)
標(biāo)準(zhǔn)庫 (1)
生成器
mysql 數(shù)據(jù)庫 (1)
第三方庫
實(shí)戰(zhàn)
運(yùn)算符
類(3)
字典(2)
語句(1)
數(shù)和四則運(yùn)算
語句(2)
文件(2)
MySQL 數(shù)據(jù)庫 (2)
電子表格
迭代器
mongodb 數(shù)據(jù)庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網(wǎng)站 (1)
標(biāo)準(zhǔn)庫 (5)
函數(shù)(4)
類(5)
字符串(2)
關(guān)于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據(jù)
常用數(shù)學(xué)函數(shù)和運(yùn)算優(yōu)先級
字符串(3)
為計(jì)算做準(zhǔn)備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯(cuò)誤和異常 (3)
分析 Hello
Python 安裝
標(biāo)準(zhǔn)庫 (2)
列表(2)
元組

除法

除法啰嗦,不僅是 Python。

整數(shù)除以整數(shù)

進(jìn)入 Python 交互模式之后(以后在本教程中,可能不再重復(fù)這類的敘述,只要看到>>>,就說明是在交互模式下),練習(xí)下面的運(yùn)算:

>>> 2 / 5
0
>>> 2.0 / 5
0.4
>>> 2 / 5.0
0.4
>>> 2.0 / 5.0
0.4

看到?jīng)]有?麻煩出來了(這是在 Python2.x 中),按照數(shù)學(xué)運(yùn)算,以上四個(gè)運(yùn)算結(jié)果都應(yīng)該是 0.4。但我們看到的后三個(gè)符合,第一個(gè)居然結(jié)果是 0。why?

因?yàn)?,?Python(嚴(yán)格說是 Python2.x 中,Python3 會有所變化)里面有一個(gè)規(guī)定,像 2/5 中的除法這樣,是要取整(就是去掉小數(shù),但不是四舍五入)。2 除以 5,商是 0(整數(shù)),余數(shù)是 2(整數(shù))。那么如果用這種形式:2/5,計(jì)算結(jié)果就是商那個(gè)整數(shù)?;蛘呖梢岳斫鉃椋?strong>整數(shù)除以整數(shù),結(jié)果是整數(shù)(商)。

比如:

>>> 5 / 2
2
>>> 7 / 2
3
>>> 8 / 2
4

注意:得到是商(整數(shù)),而不是得到含有小數(shù)位的結(jié)果再通過“四舍五入”取整。例如:5/2,得到的是商 2,余數(shù) 1,最終5 / 2 = 2。并不是對 2.5 進(jìn)行四舍五入。

浮點(diǎn)數(shù)與整數(shù)相除

這個(gè)標(biāo)題和上面的標(biāo)題格式不一樣,上面的標(biāo)題是“整數(shù)除以整數(shù)”,如果按照風(fēng)格一貫制的要求,本節(jié)標(biāo)題應(yīng)該是“浮點(diǎn)數(shù)除以整數(shù)”,但沒有,現(xiàn)在是“浮點(diǎn)數(shù)與整數(shù)相除”,其含義是:

假設(shè):x 除以 y。其中 x 可能是整數(shù),也可能是浮點(diǎn)數(shù);y 可能是整數(shù),也可能是浮點(diǎn)數(shù)。

出結(jié)論之前,還是先做實(shí)驗(yàn):

>>> 9.0 / 2
4.5
>>> 9 / 2.0
4.5
>>> 9.0 / 2.0
4.5

>>> 8.0 / 2
4.0
>>> 8 / 2.0
4.0
>>> 8.0 / 2.0
4.0

歸納,得到規(guī)律:不管是被除數(shù)還是除數(shù),只要有一個(gè)數(shù)是浮點(diǎn)數(shù),結(jié)果就是浮點(diǎn)數(shù)。所以,如果相除的結(jié)果有余數(shù),也不會像前面一樣了,而是要返回一個(gè)浮點(diǎn)數(shù),這就跟在數(shù)學(xué)上學(xué)習(xí)的結(jié)果一樣了。

>>> 10.0 / 3
3.3333333333333335

這個(gè)是不是就有點(diǎn)搞怪了,按照數(shù)學(xué)知識,應(yīng)該是 3.33333...,后面是 3 的循環(huán)了。那么你的計(jì)算機(jī)就停不下來了,滿屏都是 3。為了避免這個(gè),Python 武斷終結(jié)了循環(huán),但是,可悲的是沒有按照“四舍五入”的原則終止。當(dāng)然,還會有更奇葩的出現(xiàn):

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.1 - 0.2
0.0
>>> 0.1 + 0.1 + 0.1 - 0.3
5.551115123125783e-17
>>> 0.1 + 0.1 + 0.1 - 0.2
0.10000000000000003

越來越糊涂了,為什么 computer 姑娘在計(jì)算這么簡單的問題上,如此糊涂了呢?不是 computer 姑娘糊涂,她依然冰雪聰明。原因在于十進(jìn)制和二進(jìn)制的轉(zhuǎn)換上,computer 姑娘用的是二進(jìn)制進(jìn)行計(jì)算,上面的例子中,我們輸入的是十進(jìn)制,她就要把十進(jìn)制的數(shù)轉(zhuǎn)化為二進(jìn)制,然后再計(jì)算。但是,在轉(zhuǎn)化中,浮點(diǎn)數(shù)轉(zhuǎn)化為二進(jìn)制,就出問題了。

例如十進(jìn)制的 0.1,轉(zhuǎn)化為二進(jìn)制是:0.0001100110011001100110011001100110011001100110011...

也就是說,轉(zhuǎn)化為二進(jìn)制后,不會精確等于十進(jìn)制的 0.1。同時(shí),計(jì)算機(jī)存儲的位數(shù)是有限制的,所以,就出現(xiàn)上述現(xiàn)象了。

這種問題不僅僅是 Python 中有,所有支持浮點(diǎn)數(shù)運(yùn)算的編程語言都會遇到,它不是 Python 的 bug。

明白了問題原因,怎么解決呢?就 Python 的浮點(diǎn)數(shù)運(yùn)算而言,大多數(shù)機(jī)器上每次計(jì)算誤差不超過 2**53 分之一。對于大多數(shù)任務(wù)這已經(jīng)足夠了,但是要在心中記住這不是十進(jìn)制算法,每個(gè)浮點(diǎn)數(shù)計(jì)算可能會帶來一個(gè)新的舍入錯(cuò)誤。

一般情況下,只要簡單地將最終顯示的結(jié)果用“四舍五入”到所期望的十進(jìn)制位數(shù),就會得到期望的最終結(jié)果。

對于需要非常精確的情況,可以使用 decimal 模塊,它實(shí)現(xiàn)的十進(jìn)制運(yùn)算適合會計(jì)方面的應(yīng)用和高精度要求的應(yīng)用。另外 fractions 模塊支持另外一種形式的運(yùn)算,它實(shí)現(xiàn)的運(yùn)算基于有理數(shù)(因此像 1/3 這樣的數(shù)字可以精確地表示)。最高要求則可是使用由 SciPy 提供的 Numerical Python 包和其它用于數(shù)學(xué)和統(tǒng)計(jì)學(xué)的包。列出這些東西,僅僅是讓看官能明白,解決問題的方式很多,后面會用這些中的某些方式解決上述問題。

關(guān)于無限循環(huán)小數(shù)問題,我有一個(gè)鏈接推薦給諸位,它不是想象的那么簡單呀。請閱讀:維基百科的詞條:0.999...,會不會有深入體會呢?

補(bǔ)充一個(gè)資料,供有興趣的朋友閱讀:浮點(diǎn)數(shù)算法:爭議和限制

Python 總會要提供多種解決問題的方案的,這是她的風(fēng)格。

引用模塊解決除法--啟用輪子

Python 之所以受人歡迎,一個(gè)很重重要的原因,就是輪子多。這是比喻啦。就好比你要跑的快,怎么辦?光天天練習(xí)跑步是不行滴,要用輪子。找輛自行車,就快了很多。還嫌不夠快,再換電瓶車,再換汽車,再換高鐵...反正你可以選擇的很多。但是,這些讓你跑的快的東西,多數(shù)不是你自己造的,是別人造好了,你來用。甚至兩條腿也是感謝父母恩賜。正是因?yàn)檩喿佣?,可以選擇的多,就可以以各種不同速度享受了。

輪子是人類偉大的發(fā)明。

Python 就是這樣,有各種輪子,我們只需要用。只不過那些輪子在 Python 里面的名字不叫自行車、汽車,叫做“模塊”,有人承接別的語言的名稱,叫做“類庫”、“類”。不管叫什么名字吧。就是別人造好的東西我們拿過來使用。

怎么用?可以通過兩種形式用:

  • 形式 1:import module-name。import 后面跟空格,然后是模塊名稱,例如:import os
  • 形式 2:from module1 import module11。module1 是一個(gè)大模塊,里面還有子模塊 module11,只想用 module11,就這么寫了。

不啰嗦了,實(shí)驗(yàn)一個(gè):

>>> from __future__ import division
>>> 5 / 2
2.5
>>> 9 / 2
4.5
>>> 9.0 / 2
4.5
>>> 9 / 2.0
4.5

注意了,引用了一個(gè)模塊之后,再做除法,就不管什么情況,都是得到浮點(diǎn)數(shù)的結(jié)果了。

這就是輪子的力量。

余數(shù)

前面計(jì)算 5/2 的時(shí)候,商是 2,余數(shù)是 1

余數(shù)怎么得到?在 Python 中(其實(shí)大多數(shù)語言也都是),用%符號來取得兩個(gè)數(shù)相除的余數(shù).

實(shí)驗(yàn)下面的操作:

>>> 5 % 2
1
>>> 6%4
2
>>> 5.0%2
1.0

符號:%,就是要得到兩個(gè)數(shù)(可以是整數(shù),也可以是浮點(diǎn)數(shù))相除的余數(shù)。

前面說 Python 有很多人見人愛的輪子(模塊),她還有豐富的內(nèi)建函數(shù),也會幫我們做不少事情。例如函數(shù) divmod()

>>> divmod(5,2)  # 表示 5 除以 2,返回了商和余數(shù)
(2, 1)
>>> divmod(9,2)
(4, 1)
>>> divmod(5.0,2)
(2.0, 1.0)

四舍五入

最后一個(gè)了,一定要堅(jiān)持,今天的確有點(diǎn)啰嗦了。要實(shí)現(xiàn)四舍五入,很簡單,就是內(nèi)建函數(shù):round()

動手試試:

>>> round(1.234567,2)
1.23
>>> round(1.234567,3)
1.235
>>> round(10.0/3,4)
3.3333

簡單吧。越簡單的時(shí)候,越要小心,當(dāng)你遇到下面的情況,就有點(diǎn)懷疑了:

>>> round(1.2345,3)
1.234               # 應(yīng)該是:1.235
>>> round(2.235,2)
2.23                # 應(yīng)該是:2.24

哈哈,我發(fā)現(xiàn)了 Python 的一個(gè) bug,太激動了。

別那么激動,如果真的是 bug,這么明顯,是輪不到我的。為什么?具體解釋看這里,下面摘錄官方文檔中的一段話:

Note: The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information.

原來真的輪不到我。歸根到底還是浮點(diǎn)數(shù)中的十進(jìn)制轉(zhuǎn)化為二進(jìn)制惹的禍。

似乎除法的問題到此要結(jié)束了,其實(shí)遠(yuǎn)遠(yuǎn)沒有,不過,做為初學(xué)者,至此即可。還留下了很多話題,比如如何處理循環(huán)小數(shù)問題,我肯定不會讓有探索精神的朋友失望的,在我的 github 中有這樣一個(gè)輪子,如果要深入研究,可以來這里嘗試。


總目錄   |   上節(jié):數(shù)和四則運(yùn)算   |   下節(jié):Math 模塊和運(yùn)算優(yōu)先級

如果你認(rèn)為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。

上一篇:生成器下一篇:集合(2)