自己做網(wǎng)站可以掙錢嗎windows優(yōu)化大師怎么使用
文章目錄
- python round(num, n)小數(shù)四舍五入
- python round(num, n)基礎(chǔ)
- 銀行家舍入(Banker's Rounding)
- 利息被銀行四舍五入后,你到底是賺了還是虧了?
- python小數(shù)位的使用decimal模塊四舍五入(解決round 遇5不進(jìn))
python round(num, n)小數(shù)四舍五入
python round(num, n)基礎(chǔ)
round函數(shù)執(zhí)行的是標(biāo)準(zhǔn)的四舍五入操作。
> round( number [, ndigits] )
# number:要四舍五入的數(shù),ndigits:要小數(shù)點(diǎn)后保留的位數(shù)。ndigits為保留的小數(shù)位數(shù),不加ndigits則只保留x四舍五入后的整數(shù)部分。
round函數(shù)的語法結(jié)構(gòu)為:ndigits為小數(shù)點(diǎn)后保留的位數(shù)、其中number為需要進(jìn)行四舍五入的數(shù)字,round(number,ndigits)。即進(jìn)行整數(shù)舍入、則默認(rèn)為0,如果ndigits未指定。
然而,對(duì)于某些特定的情況,round函數(shù)可能會(huì)出現(xiàn)不符合預(yù)期的行為。
>>> round(2.45, 1)
2.5
>>> round(2.675, 2)
2.67
結(jié)果都應(yīng)該是2.68的,結(jié)果它偏偏是2.67,為什么?
原因分析:
這跟浮點(diǎn)數(shù)的精度有關(guān)。我們知道在機(jī)器中浮點(diǎn)數(shù)不一定能精確表達(dá),因?yàn)閾Q算成一串1和0后可能是無限位數(shù)的,機(jī)器已經(jīng)做出了截?cái)嗵幚怼D敲丛跈C(jī)器中保存的2.675這個(gè)數(shù)字就比實(shí)際數(shù)字要小那么一點(diǎn)點(diǎn)。這一點(diǎn)點(diǎn)就導(dǎo)致了它離2.67要更近一點(diǎn)點(diǎn),所以保留兩位小數(shù)時(shí)就近似到了2.67。
例如:
>>> round(3.1456, 2)
3.15
>>> round(3.1415, 2)
3.14
當(dāng)指定取舍的小數(shù)點(diǎn)位數(shù)的時(shí)候,一般情況也是使用四舍五入的規(guī)則,但是碰到.5的情況時(shí),如果要取舍的位數(shù)前的小數(shù)是奇數(shù),則直接舍棄,如果是偶數(shù)則向上取舍。
>>> from decimal import Decimal
>>> import decimal
>>> from decimal import Decimal
>>> print(Decimal(2.6750))
2.67499999999999982236431605997495353221893310546875
>>> print(Decimal(2.675))
2.67499999999999982236431605997495353221893310546875
>>> print(Decimal(2.6751))
2.675100000000000033395508580724708735942840576171875
用二進(jìn)制轉(zhuǎn)化的是有精度損失.部分小數(shù)無法完全用二進(jìn)制表示,round 本身沒有問題,而是二進(jìn)制保存的值有點(diǎn)誤差導(dǎo)致的。
銀行家舍入(Banker’s Rounding)
銀行家舍入法是由IEEE 754標(biāo)準(zhǔn)規(guī)定的浮點(diǎn)數(shù)取整算法 [1],大部分的編程軟件都使用的是這種方法。 所謂銀行家舍入法,其實(shí)質(zhì)是一種四舍六入五取偶(又稱四舍六入五留雙)法。
這不是bug,而是一種常見的舍入法,名稱是“銀行家式舍入法”,
用意是一半舍一半入,如果碰到0.5全入,那么銀行覺得自己虧了,
銀行希望和用戶要風(fēng)險(xiǎn)對(duì)半。不光Python,其他的計(jì)算機(jī)語言都是這個(gè)方法
這一方式的另一個(gè)常見名稱為“銀行家舍入”,是IEEE754標(biāo)準(zhǔn)的推薦舍入標(biāo)準(zhǔn)。這一方式跟通常的四舍五入相比,平均數(shù)方面更能保持原有數(shù)據(jù)的特性。
四舍六入五考慮,五后非空就進(jìn)一,五后為空看奇偶,五前為偶應(yīng)舍去,五前為奇要進(jìn)一。 其實(shí)大多數(shù)編程語言在浮點(diǎn)數(shù)的運(yùn)算上或者保留小數(shù)位上都是使用的銀行家舍入法。
利息被銀行四舍五入后,你到底是賺了還是虧了?
漲知識(shí)丨利息被銀行四舍五入后,你到底是賺了還是虧了?
參考URL: https://m.thepaper.cn/baijiahao_8230554
大家在小學(xué)就會(huì)學(xué)四舍五入對(duì)吧,四及以下被舍去,五以及更大的數(shù)字則進(jìn)1。
這個(gè)在平時(shí)做題的時(shí)候沒有什么問題,畢竟做錯(cuò)做對(duì)也不會(huì)來錢。那么問題來了,銀行交易的最小單位是分,被小數(shù)點(diǎn)約掉的錢雖然不多,但是如果按照我們小學(xué)的四舍五入,你和銀行到底誰虧誰賺呢?
四舍五入其實(shí)有不利于銀行,而有利于儲(chǔ)戶。
真正廣泛采用銀行家舍入法的,是需要更小誤差的科學(xué)和計(jì)算機(jī)系統(tǒng),因此銀行家舍入也常常叫做統(tǒng)計(jì)學(xué)家舍入(statistician’s rounding),無偏舍入(unbiased rounding)。
1940年開始,美國材料和試驗(yàn)協(xié)會(huì)(ASTM)用的就是銀行家舍入法。現(xiàn)在大部分編程軟件的默認(rèn)設(shè)置都是銀行家舍入法,比如C/C++、JavaScript、PHP、Go,英特爾處理器用的也是銀行家舍入。
python小數(shù)位的使用decimal模塊四舍五入(解決round 遇5不進(jìn))
decimal模塊
在做小數(shù)運(yùn)算或者四舍五入時(shí)怎么避免,數(shù)據(jù)不精確的問題呢?這就要用到Decimal模塊。
https://docs.python.org/zh-cn/3/library/decimal.html#rounding-modes
>>> import decimal
>>> from decimal import Decimal
>>> a = "1.345"
>>> a_t = Decimal(a).quantize(Decimal("0.00"), rounding=decimal.ROUND_HALF_UP)
>>> print(a_t)
1.35
四舍五入是基于十進(jìn)制的,在二進(jìn)制無法精確表示的時(shí)候是會(huì)有誤差的。
任何需要十進(jìn)制運(yùn)算的地方,都需要用 decimal.Decimal 取代 float:
from _pydecimal import Decimal, Context, ROUND_HALF_UP
print(Context(prec=3, rounding=ROUND_HALF_UP).create_decimal('1.325'))
- ROUND_HALF_UP 我們熟悉的四舍五入
- ROUND_HALF_EVEN 四舍六入五成雙
我們抽象成正常的函數(shù)方便使用:
import decimaldef normal_round(n, decimal_places):"""進(jìn)行正常的四舍五入,并指定保留的小數(shù)位數(shù)"""context = decimal.getcontext()context.rounding = decimal.ROUND_HALF_UProunded_value = round(decimal.Decimal(n), decimal_places)return rounded_valueoverall_score = 87.565
grade = normal_round(overall_score, 2)
print(grade)
執(zhí)行結(jié)果:
>>> round(87.565, 2)
87.56
>>> import decimal
>>>
>>> def normal_round(n, decimal_places):
... """進(jìn)行正常的四舍五入,并指定保留的小數(shù)位數(shù)"""
... context = decimal.getcontext()
... context.rounding = decimal.ROUND_HALF_UP
... rounded_value = round(decimal.Decimal(n), decimal_places)
... return rounded_value
...
>>> overall_score = 87.565
>>> grade = normal_round(overall_score, 2)
>>> print(grade)
87.56
>>>
注意:normal_round函數(shù)返回的是decimal.Decimal類型的對(duì)象,而不是浮點(diǎn)數(shù)。
數(shù)據(jù)庫操作可能不支持decimal.Decimal類型的參數(shù)。對(duì)于這種情況,你可以將normal_round函數(shù)返回的結(jié)果轉(zhuǎn)換為浮點(diǎn)數(shù)或字符串,以適應(yīng)數(shù)據(jù)庫操作的要求。
import decimaldef normal_round(n, decimal_places):"""進(jìn)行正常的四舍五入,并指定保留的小數(shù)位數(shù)"""context = decimal.getcontext()context.rounding = decimal.ROUND_HALF_UProunded_value = round(decimal.Decimal(n), decimal_places)return float(rounded_value)
在這個(gè)修改后的函數(shù)中,我們使用 float 函數(shù)將 rounded_value 轉(zhuǎn)換為浮點(diǎn)數(shù)類型。這樣,normal_round 函數(shù)將返回一個(gè)浮點(diǎn)數(shù),而不是 decimal.Decimal 對(duì)象。