小數(shù)點后如何處理?

今天我們的任務(wù)是小數(shù)點后如何處理?

《流暢的Python》一書中談到python語言優(yōu)秀特性之一,就是通過豐富的參數(shù)控制表達(dá)不同的策略。Python 內(nèi)置的 round() 函數(shù)使用了哪種四舍五入策略?

How to Round Half to Even 一文中提到:
round() 函數(shù)使用 了 "round half to even" 策略:
具體看下面兩個向前一位取整的效果,特別注意并非是我們熟悉的四舍五入?。?!

第一種策略不做任何參數(shù)控制,即默認(rèn)用法

Defaults to: decimal.ROUND_HALF_UP
默認(rèn)為: decimal.ROUND_HALF_UP

現(xiàn)在通過round保留小數(shù)點后2位,原來的數(shù)是小數(shù)點末位,即下面的例子就是第3位,那么先看:
1、小數(shù)點后第3位是 > 5,還是 <= 5,決定了是否向第2位進(jìn)位。再看
2、小數(shù)點后末位小于等于5時,小數(shù)點后第2位的數(shù)是奇數(shù)還是偶數(shù)!

如果是奇數(shù),那么向偶數(shù)取整
如果是偶數(shù),那么保持偶數(shù)不變

print('-2.535保留2位 :',round(-2.535,2))
-2.54

print('-2.545保留2位 :',round(-2.545,2))
-2.54

print('-2.546保留2位 :',round(-2.546,2))
#-2.55

print('-2.595保留2位 :',round(-2.595,2))
-2.6

print(round(-2.541,2))
-2.54

print(round(-2.545,2))
-2.54

多選擇不同臨界點附近的小數(shù),體會差別:

通過實際輸出總結(jié)規(guī)律,對策略理解由幫助!

print('-2.535保留2位 :',round(-2.535,2))
-2.54

print('-2.545保留2位 :',round(-2.545,2))
-2.54

print('-2.575保留2位 :',round(-2.575,2))
-2.58

print('-2.595保留2位 :',round(-2.595,2))
-2.6

print(round(-1.225, 2))
-1.23

print(round(1.74,1))
1.7

print(round(1.75,1))
1.8

print(round(1.74))
2

print(round(-2.961,2))
-2.96

print(round(-2.961,1))
-3.0

print(round(-2.961))
-3


print('-2.535,2精確到點后兩位: ', round(-2.535,2))
-2.535,2: -2.54

print(round(-2.546,2))
-2.55

print(round(-2.441,1))
-2.4

print(round(-2.941))
-3

如果不使用內(nèi)置庫函數(shù),如何實現(xiàn)

def rounding(number, levels = 2, up = False):
    n = number * (10 ** levels)
    nint = int(n)
    up = 1 if (up is True and number > 0) or (up is False and number < 0) else 0
    return (nint + round(n - nint + up) - up) / (10 ** levels)
print(rounding(3.1415))
3.14

def rounding(number, levels = 3, up = True):
    n = number * (10 ** levels)
    nint = int(n)
    up = 1 if (up is True and number > 0) or (up is False and number < 0) else 0
    return (nint + round(n - nint + up) - up) / (10 ** levels)
print(rounding(3.1415))
3.142

使用庫函數(shù)的優(yōu)點是無需自己“造輪子”。除了上述策略,round還有需要聲明的策略,用法不同的定義

向上取整:math.ceil
向下取整:math.floor

 - decimal.ROUND_CEILING (towards Infinity)
ROUND_CEILING (朝向無窮大)
  
- decimal.ROUND_DOWN (towards zero)
ROUND_DOWN (向零方向)
   
- decimal.ROUND_FLOOR (towards -Infinity)
ROUND_FLOOR (向-無窮遠(yuǎn))
 
- decimal.ROUND_HALF_DOWN (to nearest with ties going towards zero)
ROUND_HALF_DOWN (向零點并列的最接近者)
    
- decimal.ROUND_HALF_EVEN (to nearest with ties going to nearest even integer)
ROUND_HALF_EVEN (向最接近的偶數(shù)整數(shù)并列)
    
- decimal.ROUND_HALF_UP (to nearest with ties going away from zero)
ROUND_HALF_UP (向最接近的并列零點前進(jìn))
  
 - decimal.ROUND_UP (away from zero)
ROUND_UP (遠(yuǎn)離零點)
   
- decimal.ROUND_05UP (away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise towards zero)
如果四舍五入后最后一位數(shù)字為0或5,則遠(yuǎn)離零;否則為零

測試任務(wù)1:只取得小數(shù)部分時該如何操作?
如何實現(xiàn)下列效果
get_decimal(2.4) # ouput: 0.4
get_decimal(-0.9) # ouput: 0.9

def get_decimal(n):
    return abs(n) % 1

測試任務(wù)2:只取到第n位小數(shù)時,該如何操作?
10.1289767789 --> 10.12
-7488.83485834983 --> -7488.83
4.653725356 --> 4.65

def two_decimal_places(number):
    return int(number * 100) / 100.0

測試任務(wù)3:只取得小數(shù)部分時該如何操作?

Example:
5.5589 is rounded 5.56
3.3424 is rounded 3.34

下面三種寫法均能實現(xiàn)以上任務(wù):

#1st
def two_decimal_places(n):
      return round(n, 2)

#2nd
def two_decimal_places(n):
   return round(n* 100) / 100

#3rd
from numpy import round
def two_decimal_places(n):
    return round(n, decimals=2)

深入函數(shù)內(nèi)部:

丁丁貓鼓勵同學(xué)實現(xiàn)一些python內(nèi)置得庫函數(shù),這樣做的價值一舉兩得。既可以鍛煉對函數(shù)的深入理解,往往庫函數(shù)用到的算法是高頻率常用的算法,寫一個stack棧的彈出、壓棧等操作是非常鍛煉的好任務(wù)!

例如:寫一個函數(shù)名為ceil()的函數(shù),實現(xiàn)相當(dāng)于math.ceil()內(nèi)置函數(shù)的功能

def ceil(x) -> int:
    """
    Return the ceiling of x as an Integral.
    :param x: the number
    :return: the smallest integer >= x.
    """
    return (
        x if isinstance(x, int) or x - int(x) == 0 else int(x + 1) if x > 0 else int(x)
    )


if __name__ == "__main__":
    import doctest

    doctest.testmod()

print(ceil(3.1415))

#對比內(nèi)置函數(shù)math.ceil()
import math
print(math.ceil(3.1415))

4
4

綜合任務(wù)實踐

編寫一個函數(shù),它以非負(fù)整數(shù)(秒)作為輸入,并以可讀格式(HH:MM:SS)返回時間
例如:一部按秒計費的充電樁,顯示充電時間是4898秒,現(xiàn)在你寫一個函數(shù)換算為小時,分鐘和秒的格式顯示:[hh:mm:ss],數(shù)字大小范圍如下所示:

HH = hours, padded to 2 digits, range: 00 – 99
HH=小時,填充到2位數(shù),范圍:00-99

MM = minutes, padded to 2 digits, range: 00 – 59
MM=分鐘,填充到2位數(shù),范圍:00-59

SS = seconds, padded to 2 digits, range: 00 – 59
SS=秒,填充到2位數(shù),范圍:00-59

The maximum time never exceeds 359999 (99:59:59)
最大時間從不超過359999(99∶59∶59)

def make_readable(seconds):
    hours, seconds = divmod(seconds, 60 ** 2)
    minutes, seconds = divmod(seconds, 60)
    return '{:02}:{:02}:{:02}'.format(hours, minutes, seconds)

01:21:38

divmod():非常有用的內(nèi)置函數(shù)

編寫Python函數(shù)round_half_towards_zero的代碼
該函數(shù)接收一個數(shù)字n和一個默認(rèn)為0的關(guān)鍵字參數(shù)小數(shù),并返回n的值四舍五入到小數(shù)點后的數(shù)值,其中的平分是四舍五入到零。

你可以假設(shè)已經(jīng)導(dǎo)入了數(shù)學(xué)模塊,并且存在一個名為round_half_down()的函數(shù),該函數(shù)接收兩個參數(shù)--一個數(shù)字n和一個關(guān)鍵字參數(shù)decimals,并返回數(shù)字n四舍五入到小數(shù)點后的數(shù)值,其中的平分線向下舍入。

這就是我們期望看到的:

def round_half_towards_zero(n, decimals=0):
  rounded_abs = round_half_down(abs(n), decimals)
  return math.copysign(rounded_abs, n)

# Also acceptable:
def round_half_towards_zero(n, decimals=0):
  sign = 1 if n >= 0 else -1
  rounded_abs = round_half_down(abs(n), decimals)
  return sign * rounded_abs

# Without "round_half_down()":
def round_half_towards_zero(n, decimals=0):
  sign = 1 if n >= 0 else -1
  multiplier = 10 ** decimals
  rounded_abs = math.ceil(abs(n)*multiplier - 0.5) / multiplier
  return sign * rounded_abs

總結(jié)篇:四舍五入的影響有多大?

四舍五入的錯誤曾左右了選舉,甚至導(dǎo)致了生命的損失。

如何對數(shù)字進(jìn)行四舍五入是很重要的,作為一個負(fù)責(zé)任的開發(fā)者和軟件設(shè)計師,你需要知道常見的問題是什么以及如何處理這些問題。讓我們深入研究一下不同的四舍五入方法是什么,以及如何在純Python中實現(xiàn)每一種方法。

假設(shè)你有一個非常幸運的一天,發(fā)現(xiàn)地上有100元錢。與其一次花光所有的錢,你決定精打細(xì)算,通過購買一些不同的股票來投資你的錢。

股票的價值取決于供求關(guān)系。想買股票的人越多,該股票的價值就越大,反之亦然。在高成交量的股票市場上,某只股票的價值會以秒為單位進(jìn)行波動。

我們來做個小實驗。我們假設(shè)你所購買的股票的整體價值每秒鐘都會有一些小的隨機(jī)數(shù)波動,比如說在0.05美元和-0.05美元之間。這個波動不一定是一個只有兩位小數(shù)的漂亮數(shù)值。例如,總價值可能前一秒增加0.031286美元,下一秒減少0.028476美元。

你不想把你的數(shù)值記錄到小數(shù)點后第五或第六位,所以你決定砍掉小數(shù)點后第三位的所有數(shù)值。在四舍五入的行話中,這叫做將數(shù)字截斷到小數(shù)點后第三位。這里會有一些誤差,但通過保留三位小數(shù),這個誤差不會很大。對吧?

為了使用Python運行我們的實驗,我們先寫一個truncate()函數(shù),將一個數(shù)字截斷到小數(shù)點后三位。

truncate()函數(shù)的工作原理是首先將數(shù)字n的小數(shù)點向右移動三位,將n乘以1000。這個新數(shù)字的整數(shù)部分用int()表示。最后,將小數(shù)點向左移三位,將n除以1000。
接下來,讓我們定義模擬的初始參數(shù)。你需要兩個變量:一個用來跟蹤模擬完成后股票的實際值,一個用來跟蹤每一步截斷到小數(shù)點后三位的股票值。
首先將這些變量初始化為100。

actual_value, truncated_value = 100, 100。

現(xiàn)在讓我們運行模擬100萬秒(約11.5天)。每一秒鐘,用隨機(jī)模塊中的uniform()函數(shù)生成一個介于-0.05和0.05之間的隨機(jī)值,然后更新實際值和截斷值。

import random

random.seed(100)

for _ in range(1000000):
... randn = random.uniform(-0.05, 0.05)
... actual_value = actual_value + randn
... truncated_value = truncate(truncated_value + randn)
...

actual_value
96.45273913513529

truncated_value
0.239

仿真的主要部分發(fā)生在for循環(huán)中,它在0到999,999之間的數(shù)字范圍(1000000)中循環(huán)。每一步從range()中得到的值都存儲在變量_中,我們在這里使用這個變量是因為我們在循環(huán)中實際上不需要這個值。

在循環(huán)的每一步,使用random.randn()生成一個介于-0.05和0.05之間的新隨機(jī)數(shù),并分配給變量randn。通過將randn加到actual_value中計算出你的投資新值,通過將randn加到truncated_value中,然后用truncate()將這個值截斷,計算出截斷后的總數(shù)。

通過檢查運行循環(huán)后的 actual_value 變量可以看出,你只損失了大約 3.55 美元。然而,如果你一直在看truncated_value,你會認(rèn)為你幾乎失去了所有的錢!你會發(fā)現(xiàn),你的錢幾乎都被保留小數(shù)的取整操作近清零了。

注意:在上面的例子中random.seed()函數(shù)是用來給偽隨機(jī)數(shù)生成器播種的,這樣你就可以重現(xiàn)這里的輸出。

要了解更多關(guān)于Python中的隨機(jī)性,請查看Real Python的《在Python中生成隨機(jī)數(shù)據(jù)(指南)》。

暫且不考慮 round() 的表現(xiàn)并不完全如你所愿,讓我們嘗試重新運行模擬。這次我們將使用 round() 在每一步都取整到小數(shù)點后三位,然后再次使用 seed() 進(jìn)行模擬,得到與之前相同的結(jié)果。

random.seed(100)
actual_value, rounded_value = 100, 100

for _ in range(1000000):
... randn = random.uniform(-0.05, 0.05)
... actual_value = actual_value + randn
... rounded_value = round(rounded_value + randn, 3)
...

actual_value
96.45273913513529

rounded_value
96.258

多么大的差別啊!
雖然看起來令人震驚,但這個確切的錯誤在20世紀(jì)80年代初引起了相當(dāng)大的轟動,當(dāng)時為記錄溫哥華證券交易所價值而設(shè)計的系統(tǒng)將總指數(shù)值截斷到小數(shù)點后三位,而不是四舍五入。四舍五入的錯誤曾左右了選舉,甚至導(dǎo)致了生命的損失。

round共有八種取整的策略
Truncation

Rounding Up

Rounding Down

Interlude: Rounding Bias

Rounding Half Up

Rounding Half Down

Rounding Half Away From Zero

Rounding Half To Even

ROUND DOWN的含義是,向0的方向舍入,取滿足小數(shù)點后位數(shù)的需要后,最靠經(jīng)0的那個數(shù)。從數(shù)軸上來看,就是向中心的0點靠近。( Round towards zero. )
在python中,int()函數(shù)對浮點數(shù)的取整,就是采用的ROUND DOWN方式:

int(1.2)
1
int(1.9)
1
int(-1.2)
-1
int(-1.9)
-1

Python 內(nèi)置的 round() 函數(shù)使用了哪種四舍五入策略?
How to Round Half to Even 一文中提到:
round() 函數(shù)使用 了 "round half to even" 策略:

-2.535保留2位 : -2.54
-2.545保留2位 : -2.54
-2.575保留2位 : -2.58
-2.595保留2位 : -2.6

print('-2.535保留2位 :',round(-2.535,2))
-2.54

print('-2.545保留2位 :',round(-2.545,2))
-2.54

print('-2.595保留2位 :',round(-2.595,2))

-2.6

"四舍五入到偶數(shù) "的策略,四舍五入到最接近的偶數(shù)。例如:0.465取小數(shù)點后兩位該如何運用策略?
首先,小數(shù)點向右移動3位,變?yōu)?6.5,落在46-47之間。就近原則看離46.5最近的偶數(shù)是46,結(jié)果是0.46

ROUND HALF EVEN也被稱為銀行家舍入法,這種舍入方法的規(guī)則是:向離最近的偶數(shù)靠 Round to nearest with ties going to nearest even integer.

"四舍五入到偶數(shù) "的策略的優(yōu)點?
四舍五入到偶數(shù) "策略沒有基于數(shù)據(jù)集中紐帶符號的偏差。如果數(shù)據(jù)集中有更多的紐帶四舍五入到偶數(shù),而不是四舍五入,它可能會引入一個偏差,但這種情況發(fā)生的概率通常很低。在這里介紹的所有選擇中,"四舍五入到偶數(shù) "的偏差最小。

python內(nèi)置的round函數(shù),采用的就是ROUND HALF EVEN舍入方法,round函數(shù)不是在做四舍五入:

在Python中對數(shù)字進(jìn)行四舍五入,用 "四舍五入 "的策略將1.73四舍五入到小數(shù)點后一位是:
1.7

1.8

print(round(1.74,1))
1.7
print(round(1.75,1))
1.8
print(round(1.74))
2

首先,將小數(shù)點向右移動一位,得到17.3

然后四舍五入到最接近的整數(shù),也就是18.

將小數(shù)點后移一位,得到1.8

最后,將小數(shù)點后移一位,得到1.8。

用 "四舍五入 "的策略將數(shù)值-2.961四舍五入到小數(shù)點后兩位,則...
-2.97
-2.96
將小數(shù)點向右移動兩位,得到-296.1

print(round(-2.961,2))
-2.96

print(round(-2.961,1))
-3.0

print(round(-2.961))
-3
然后四舍五入到最接近的整數(shù),在本例中是-297,因為四舍五入總是將數(shù)字向左舍入(向負(fù)無窮大)最后,將小數(shù)點后移兩位,得到-2.97

print(round(-2.541,2))
-2.54
print(round(-2.545,2))
-2.54
print(round(-2.546,2))
-2.55
當(dāng)一個數(shù)保留到小數(shù)點后3位時,以下哪項是真的?

正數(shù)被向下舍入,負(fù)數(shù)被向上舍入。

正數(shù)和負(fù)數(shù)都是四舍五入。

正數(shù)是四舍五入,負(fù)數(shù)是四舍五入。

正數(shù)和負(fù)數(shù)都是四舍五入的。

當(dāng)你把一個正數(shù)保留時,你只需把四舍五入后的數(shù)字截斷。
例如,將1.7365截斷到小數(shù)點后三位,結(jié)果是1.736。結(jié)果與四舍五入到小數(shù)點后三位的結(jié)果是一樣的。
另一方面,將-1.7365截斷到三位小數(shù),結(jié)果是-1.736,在數(shù)字線上是-1.7365的右邊,因此與四舍五入到三位小數(shù)相同。

用 "離零點半圓 "策略將-0.045四舍五入到小數(shù)點后2位的值是...
-0.05
-0.04

當(dāng)你 "四舍五入到零 "的時候,你把正數(shù)的和值向上舍,負(fù)數(shù)的向下舍。
將-0.045中的小數(shù)點向右移動兩位小數(shù),得到-4.5。這正好介于-4和-5之間,但由于我們是從零開始四舍五入的,所以我們四舍五入到-5。
最后,將小數(shù)點向左后移兩位,得到 -0.05。

使用 "四舍五入 "策略將4.65四舍五入到小數(shù)點后一位的值是......。
4.7
4.6

首先,將小數(shù)點向右移動一位,得到46.5。這正好是46和47之間的一半。
根據(jù) "四舍五入到偶數(shù) "的策略,我們應(yīng)該把46.5四舍五入到最接近的偶數(shù),也就是46。將小數(shù)點向左后移一位,得到4.6。

ROUND FLOOR
floor是地板的意思,ROUND FLOOR的意思,就是向下舍入,下的方向,在數(shù)軸上是向著負(fù)無窮的方向 Round towards -Infinity

python的 // 符號,做的計算,就是ROUND FLOOR,如果有float參與//運算,結(jié)果就是float:

3//2
1
7//2
3
7//-2
-4
-3//2
-2
7//2.1
3.0
7.1//2
3.0
7.1//2.1
3.0

ROUND CEILING
從這里開始,后續(xù)所有的舍入方法,都只在decimal模塊中支持。
ROUND CEILING對應(yīng)ROUND FLOOR,表示向上舍入,上就是無窮大的方向 Round towards Infinity

Decimal('1.234').quantize(Decimal('.00'), rounding=ROUND_CEILING)
Decimal('1.24')
Decimal('-1.234').quantize(Decimal('.00'), rounding=ROUND_CEILING)
Decimal('-1.23')

ROUND UP
ROUND UP對應(yīng)ROUND DOWN,永遠(yuǎn)向著遠(yuǎn)離0的方向舍入Round away from zero.

Decimal('1.234').quantize(Decimal('.00'), rounding=ROUND_UP)
Decimal('1.24')
Decimal('-1.234').quantize(Decimal('.00'), rounding=ROUND_UP)
Decimal('-1.24')

ROUND HALF DOWN
就近舍入,如果與兩邊的數(shù)距離相等,向0方向舍入Round to nearest with ties going towards zero.

Decimal('1.235').quantize(Decimal('.00'), rounding=ROUND_HALF_DOWN)
Decimal('1.23')
Decimal('-1.235').quantize(Decimal('.00'), rounding=ROUND_HALF_DOWN)
Decimal('-1.23')

ROUND HALF UP
就近舍入,如果與兩邊的數(shù)距離相等,向遠(yuǎn)離0的方向舍入Round to nearest with ties going away from zero.

Decimal('1.235').quantize(Decimal('.00'), rounding=ROUND_HALF_UP)
Decimal('1.24')
Decimal('-1.235').quantize(Decimal('.00'), rounding=ROUND_HALF_UP)
Decimal('-1.24')

ROUND 05UP
Round away from zero if last digit after rounding towards zero would have been 0 or 5; otherwise round towards zero. 如果rounding之后,最后的數(shù)字是0或5,就向UP方向(遠(yuǎn)離0的方向)舍入;否則,就像靠近0的方向舍入。

Decimal('1.204').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('1.21')
Decimal('1.254').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('1.26')

Decimal('1.214').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('1.21')
Decimal('1.274').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('1.27')

Decimal('-1.204').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('-1.21')
Decimal('-1.254').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('-1.26')

Decimal('-1.214').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('-1.21')
Decimal('-1.274').quantize(Decimal('.00'), rounding=ROUND_05UP)
Decimal('-1.27')

以下哪種四舍五入策略最能減輕四舍五入的偏差?

四舍五入 "策略會將每個數(shù)字都向下舍入,所以這總是會引入一個向負(fù)無窮大的舍入偏差。
每當(dāng)數(shù)據(jù)集中正數(shù)的數(shù)量等于負(fù)數(shù)的數(shù)量時,"截斷 "策略就會相當(dāng)好地處理偏差,但除此之外會引入一個偏差。
"舍半而上 "策略一般不會出現(xiàn)偏差,但只要數(shù)據(jù)集中有大量的平局,就會引入一輪向正無窮大的偏差。
"整半離零 "策略比 "整半向上 "能更好地緩解偏差,但如果數(shù)據(jù)集中所有的紐帶都是正數(shù),或者所有的紐帶都是負(fù)數(shù),就會引入一個偏差。

最后,"四舍五入到偶數(shù) "策略沒有基于數(shù)據(jù)集中紐帶符號的偏差。如果數(shù)據(jù)集中有更多的紐帶四舍五入到偶數(shù),而不是四舍五入,它可能會引入一個偏差,但這種情況發(fā)生的概率通常很低。在這里介紹的所有選擇中,"四舍五入到偶數(shù) "的偏差最小。

為什么 round(-1.225, 2) 返回-1.23,而它應(yīng)該返回-1.22?
浮點表示錯誤

-1.23
因為round()應(yīng)該將平局四舍五入到最接近的偶數(shù),在本例中是-1.22。
發(fā)生這種情況的原因與機(jī)器上存儲浮點數(shù)的方式有關(guān)。

用來表示-1.22的二進(jìn)制是一個無限重復(fù)的分?jǐn)?shù),它不能準(zhǔn)確地存儲在內(nèi)存中。計算機(jī)將這個分?jǐn)?shù)四舍五入到可以存儲在內(nèi)存中的最接近的二進(jìn)制小數(shù),這個小數(shù)比-1.225略小。所以內(nèi)存中存儲的-1.225這個數(shù)其實并不是平局,round(-1.225,2)將其四舍五入到-1.23`。

更詳細(xì)的解釋請參見《如何在 Python 中對數(shù)字進(jìn)行四舍五入》一文中的旁白。

更詳細(xì)的解釋請參見 How to Round Half Down 一節(jié)中的旁白:How to Round Numbers in Python article。

假設(shè)你有下面的 Python 列表。
data = [0.15, -1.45, 3.65, -7.05, 2.45] 。

如果使用 "四舍五入 "策略將數(shù)據(jù)中的每一個數(shù)字四舍五入到小數(shù)點后一位,會產(chǎn)生以下哪種四舍五入偏差?

向正無窮大方向舍入的偏差

正確

趨向負(fù)無窮大的偏向

趨向零偏差

沒有引入四舍五入的偏差

使用 "四舍五入 "策略,數(shù)據(jù)中的每一個數(shù)字都被四舍五入到小數(shù)點后一位,結(jié)果是以下列表。
[0.2, -1.4, 3.7, -7.0, 2.5]

新列表中的每一個數(shù)字都比數(shù)據(jù)中的對應(yīng)數(shù)字大,所以引入了一個向正無窮大的四舍五入的偏向。

Flag
Rounding Strategy
decimal.ROUND_CEILING
Rounding up
decimal.ROUND_FLOOR
Rounding down
decimal.ROUND_DOWN
Truncation
decimal.ROUND_UP
Rounding away from zero
decimal.ROUND_HALF_UP
Rounding half away from zero
decimal.ROUND_HALF_DOWN
Rounding half towards zero
decimal.ROUND_HALF_EVEN
Rounding half to even
decimal.ROUND_05UP
Rounding up and rounding towards zero

編寫Python函數(shù)round_half_towards_zero的代碼,該函數(shù)接收一個數(shù)字n和一個默認(rèn)為0的關(guān)鍵字參數(shù)小數(shù),并返回n的值四舍五入到小數(shù)點后的數(shù)值,其中的平分是四舍五入到零。

你可以假設(shè)已經(jīng)導(dǎo)入了數(shù)學(xué)模塊,并且存在一個名為round_half_down()的函數(shù),該函數(shù)接收兩個參數(shù)--一個數(shù)字n和一個關(guān)鍵字參數(shù)decimals,并返回數(shù)字n四舍五入到小數(shù)點后的數(shù)值,其中的平分線向下舍入。

這就是我們期望看到的。

def round_half_towards_zero(n, decimals=0):
rounded_abs = round_half_down(abs(n), decimals)
return math.copysign(rounded_abs, n)

Also acceptable:

def round_half_towards_zero(n, decimals=0):
sign = 1 if n >= 0 else -1
rounded_abs = round_half_down(abs(n), decimals)
return sign * rounded_abs

Without round_half_down():

def round_half_towards_zero(n, decimals=0):
sign = 1 if n >= 0 else -1
multiplier = 10 ** decimals
rounded_abs = math.ceil(abs(n)*multiplier - 0.5) / multiplier
return sign * rounded_abs

-------------結(jié)束--------------

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容