A következőkben azt mutatjuk be, hogyan kerekíthetünk számokat Pythonban kerekítéssel vagy páros számra kerekítéssel. A számokról feltételezzük, hogy lebegőpontos float vagy integer int típusúak.
- beépített függvény (pl. programozási nyelvben):
round()
- A tizedesjegyeket tetszőleges számú számjegyre kerekítheti.
- Egész számok kerekítése tetszőleges számú számjegyre.
- round() páros számra kerekít, nem pedig egy közös kerekítésre.
- szabványos könyvtár
decimal
quantize()
Decimal
Objektum létrehozása- Tizedesjegyek kerekítése tetszőleges számjegyekre és kerekítés páros számokra
- Egész számok kerekítése tetszőleges számú számjegyre és kerekítés páros számokra
- Új függvény definiálása
- A tizedesjegyeket tetszőleges számú számjegyre kerekítheti.
- Egész számok kerekítése tetszőleges számú számjegyre
- Megjegyzés: Negatív értékek esetén
Vegyük észre, hogy mint fentebb említettük, a beépített round függvény nem általános kerekítés, hanem páros számra kerekítés. A részleteket lásd alább.
beépített függvény (pl. programozási nyelvben): round()
A Round() beépített függvény. Modulok importálása nélkül használható.
Az első argumentum az eredeti szám, a második pedig a számjegyek száma (hány számjegyre kell kerekíteni).
A tizedesjegyeket tetszőleges számú számjegyre kerekítheti.
Az alábbiakban egy példa a lebegőpontos lebegőpontos típus feldolgozására.
Ha a második argumentum kimarad, akkor egész számra kerekít. A típus is integer int típus lesz.
f = 123.456 print(round(f)) # 123 print(type(round(f))) # <class 'int'>
Ha a második argumentum meg van adva, akkor egy lebegőpontos lebegőpontos típust ad vissza.
Pozitív egész szám megadása esetén a tizedesjegyet, negatív egész szám megadása esetén az egész szám helyét kell megadni. A -1 a legközelebbi tizedre kerekít, a -2 a legközelebbi századra kerekít, a 0 pedig egész számra kerekít (az első helyre), de egy float típust ad vissza, ellentétben azzal, ha elhagyja.
print(round(f, 1)) # 123.5 print(round(f, 2)) # 123.46 print(round(f, -1)) # 120.0 print(round(f, -2)) # 100.0 print(round(f, 0)) # 123.0 print(type(round(f, 0))) # <class 'float'>
Egész számok kerekítése tetszőleges számú számjegyre.
A következő példa az integer int típus feldolgozására.
Ha a második argumentum kimarad, vagy ha 0 vagy pozitív egész szám van megadva, az eredeti értéket változatlanul visszaadja. Ha negatív egész számot adunk meg, akkor a megfelelő egész számjegyre kerekítünk. Mindkét esetben egy integer int típusú értéket kapunk vissza.
i = 99518 print(round(i)) # 99518 print(round(i, 2)) # 99518 print(round(i, -1)) # 99520 print(round(i, -2)) # 99500 print(round(i, -3)) # 100000
round() páros számra kerekít, nem pedig egy közös kerekítésre.
Vegye figyelembe, hogy a Python 3-ban a beépített round() függvénnyel történő kerekítés páros számra kerekít, nem pedig általános kerekítésre.
A hivatalos dokumentáció szerint a 0,5 0-ra kerekített, az 5 0-ra kerekített, és így tovább.
print('0.4 =>', round(0.4)) print('0.5 =>', round(0.5)) print('0.6 =>', round(0.6)) # 0.4 => 0 # 0.5 => 0 # 0.6 => 1 print('4 =>', round(4, -1)) print('5 =>', round(5, -1)) print('6 =>', round(6, -1)) # 4 => 0 # 5 => 0 # 6 => 10
A páros számra kerekítés definíciója a következő.
Ha a tört 0,5-nél kisebb, kerekítse lefelé; ha a tört 0,5-nél nagyobb, kerekítse felfelé; ha a tört pontosan 0,5, kerekítse fel a le- és felkerekítés közötti páros számra.
Rounding – Wikipedia
A 0,5 nem mindig csonka.
print('0.5 =>', round(0.5)) print('1.5 =>', round(1.5)) print('2.5 =>', round(2.5)) print('3.5 =>', round(3.5)) print('4.5 =>', round(4.5)) # 0.5 => 0 # 1.5 => 2 # 2.5 => 2 # 3.5 => 4 # 4.5 => 4
Bizonyos esetekben a páros számra kerekítés definíciója nem is vonatkozik a két tizedesjegy utáni feldolgozásra.
print('0.05 =>', round(0.05, 1)) print('0.15 =>', round(0.15, 1)) print('0.25 =>', round(0.25, 1)) print('0.35 =>', round(0.35, 1)) print('0.45 =>', round(0.45, 1)) # 0.05 => 0.1 # 0.15 => 0.1 # 0.25 => 0.2 # 0.35 => 0.3 # 0.45 => 0.5
Ennek oka, hogy a tizedesjegyek nem ábrázolhatók pontosan lebegőpontos számokként, ahogyan azt a hivatalos dokumentációban is szerepel.
A round() viselkedése lebegőpontos számok esetén meglepő lehet.:Például a round(2.675, 2) a várt 2.68 helyett 2.67-et ad. Ez nem hiba.:Ez annak a ténynek az eredménye, hogy a legtöbb tizedesjegy nem ábrázolható pontosan lebegőpontos számokkal.
round() — Built-in Functions — Python 3.10.2 Documentation
Ha általános kerekítést vagy a tizedesjegyek páros számokra való pontos kerekítését szeretné elérni, használhatja a szabványos könyvtár decimális kvantálását (lásd alább), vagy definiálhat egy új függvényt.
Vegyük észre azt is, hogy a Python 2-ben a round() nem páros számra kerekít, hanem kerekít.
a szabványos könyvtár decimál kvantálás() funkciója
A szabványos könyvtár decimal modulja használható a pontos decimális lebegőpontos számok kezelésére.
A decimális modul kvantálás() metódusának használatával a kerekítési mód megadásával kerekíthetjük a számokat.
- decimal quantize() — Decimal fixed point and floating point arithmetic — Python 3.10.2 Documentation
- Rounding modes — Decimal fixed point and floating point arithmetic — Python 3.10.2 Documentation
A kvantálás() módszer kerekítési argumentumának beállított értékei a következő jelentéssel bírnak.
ROUND_HALF_UP
:Általános kerekítésROUND_HALF_EVEN
:Páros számokra kerekítés
A decimal modul egy szabványos könyvtár, így nincs szükség további telepítésre, de az importálás szükséges.
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN
Decimal objektum létrehozása
A Decimal() segítségével Decimal típusú objektumok hozhatók létre.
Ha egy float típust ad meg argumentumként, akkor láthatja, hogy az értéket valójában milyen értékként kezeli.
print(Decimal(0.05)) # 0.05000000000000000277555756156289135105907917022705078125 print(type(Decimal(0.05))) # <class 'decimal.Decimal'>
Ahogy a példában látható, a 0,05 nem pontosan 0,05-nek tekintendő. Ez az oka annak, hogy a fent leírt beépített round() függvény a példában szereplő 0,05-öt is tartalmazó tizedes értékek esetén a várttól eltérő értékre kerekít.
Mivel a 0,5 a fele (2 -1 hatványa), pontosan kifejezhető bináris jelöléssel.
print(Decimal(0.5)) # 0.5
Ha a float típus helyett a str string típust adja meg, akkor a program a pontos érték Decimal típusaként kezeli.
print(Decimal('0.05')) # 0.05
Tizedesjegyek kerekítése tetszőleges számjegyekre és kerekítés páros számokra
Hívja meg a quantize() funkciót egy Decimal típusú objektumból az érték kerekítéséhez.
A quantize() első argumentuma egy olyan karakterlánc, amelynek számjegyeinek száma megegyezik a keresett számjegyek számával, például '0.1' vagy '0.01'.
Ezen kívül a ROUNDING argumentum meghatározza a kerekítési módot; ha a ROUND_HALF_UP van megadva, akkor általános kerekítést használ.
f = 123.456 print(Decimal(str(f)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 123 print(Decimal(str(f)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)) # 123.5 print(Decimal(str(f)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 123.46
A beépített round() függvénytől eltérően a 0,5 1-re kerül kerekítésre.
print('0.4 =>', Decimal(str(0.4)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) print('0.5 =>', Decimal(str(0.5)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) print('0.6 =>', Decimal(str(0.6)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 0.4 => 0 # 0.5 => 1 # 0.6 => 1
Ha a kerekítés argumentum ROUND_HALF_EVEN értékre van állítva, a kerekítés páros számokra történik, mint a beépített round() függvényben.
Mint fentebb említettük, ha a Decimal() argumentumaként egy lebegőpontos lebegőpontos típus van megadva, akkor azt egy Decimal objektumként kezeli, amelynek értéke megegyezik a lebegőpontos típus tényleges értékével, így a kvantálás() metódus használatának eredménye eltér a várttól, akárcsak a beépített round() függvényé.
print('0.05 =>', round(0.05, 1)) print('0.15 =>', round(0.15, 1)) print('0.25 =>', round(0.25, 1)) print('0.35 =>', round(0.35, 1)) print('0.45 =>', round(0.45, 1)) # 0.05 => 0.1 # 0.15 => 0.1 # 0.25 => 0.2 # 0.35 => 0.3 # 0.45 => 0.5 print('0.05 =>', Decimal(0.05).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.15 =>', Decimal(0.15).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.25 =>', Decimal(0.25).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.35 =>', Decimal(0.35).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.45 =>', Decimal(0.45).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) # 0.05 => 0.1 # 0.15 => 0.1 # 0.25 => 0.2 # 0.35 => 0.3 # 0.45 => 0.5
Ha a Decimal() argumentuma str típusú karakterláncként van megadva, a program pontosan ilyen értékű Decimal objektumként kezeli, így az eredmény a vártnak megfelelően alakul.
print('0.05 =>', Decimal(str(0.05)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.15 =>', Decimal(str(0.15)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.25 =>', Decimal(str(0.25)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.35 =>', Decimal(str(0.35)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) print('0.45 =>', Decimal(str(0.45)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN)) # 0.05 => 0.0 # 0.15 => 0.2 # 0.25 => 0.2 # 0.35 => 0.4 # 0.45 => 0.4
Mivel a 0,5 helyesen kezelhető a float típussal, nem jelent problémát, ha egész számra kerekítéskor a Decimal() argumentumaként a float típust adjuk meg, de biztonságosabb a string str típust megadni, ha tizedesre kerekítünk.
Például a 2,675 valójában 2,67499…. float típusban. Ezért ha két tizedesjegyre akar kerekíteni, akkor a Decimal()-nak meg kell adnia egy karakterláncot, különben az eredmény eltér a várt eredménytől, akár a legközelebbi egész számra (ROUND_HALF_UP), akár páros számra (ROUND_HALF_EVEN) kerekít.
print(Decimal(2.675)) # 2.67499999999999982236431605997495353221893310546875 print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 2.67 print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 2.68 print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)) # 2.67 print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)) # 2.68
Vegye figyelembe, hogy a quantize() metódus egy Decimal típusú számot ad vissza, így ha egy float típusú számmal akar operálni, akkor azt a float() segítségével kell float típusúvá alakítania, különben hiba lép fel.
d = Decimal('123.456').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP) print(d) # 123.46 print(type(d)) # <class 'decimal.Decimal'> # print(1.2 + d) # TypeError: unsupported operand type(s) for +: 'float' and 'decimal.Decimal' print(1.2 + float(d)) # 124.66
Egész számok kerekítése tetszőleges számú számjegyre és kerekítés páros számokra
Ha egész számjegyre szeretnénk kerekíteni, az első argumentumként megadott '10' nem adja meg a kívánt eredményt.
i = 99518 print(Decimal(i).quantize(Decimal('10'), rounding=ROUND_HALF_UP)) # 99518
Ennek az az oka, hogy a quantize() a kerekítést a Decimal objektum exponensének megfelelően végzi, de a Decimal('10') exponensének értéke 0, nem pedig 1.
Tetszőleges exponens megadható az E exponens karakterlánc használatával (pl. '1E1'). Az exponens exponens az as_tuple metódusban ellenőrizhető.
print(Decimal('10').as_tuple()) # DecimalTuple(sign=0, digits=(1, 0), exponent=0) print(Decimal('1E1').as_tuple()) # DecimalTuple(sign=0, digits=(1,), exponent=1)
Így az eredmény exponenciális jelölés lesz az E használatával. Ha normál jelölést szeretne használni, vagy ha kerekítés után integer int típussal akar operálni, használja az int() funkciót az eredmény átalakítására.
print(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)) # 9.952E+4 print(int(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) # 99520 print(int(Decimal(i).quantize(Decimal('1E2'), rounding=ROUND_HALF_UP))) # 99500 print(int(Decimal(i).quantize(Decimal('1E3'), rounding=ROUND_HALF_UP))) # 100000
Ha a kerekítés argumentum ROUND_HALF_UP értékre van állítva, akkor általános kerekítésre kerül sor, például az 5 értéket 10-re kerekíti.
print('4 =>', int(Decimal(4).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) print('5 =>', int(Decimal(5).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) print('6 =>', int(Decimal(6).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))) # 4 => 0 # 5 => 10 # 6 => 10
Természetesen nem jelent problémát, ha karakterláncként adja meg.
Új függvény definiálása
A decimális modul használatának módszere pontos és biztonságos, de ha a típuskonverzióval nincs megelégedve, egy új függvényt is definiálhat az általános kerekítés eléréséhez.
Ennek számos lehetséges módja van, például a következő függvény.
def my_round(val, digit=0): p = 10 ** digit return (val * p * 2 + 1) // 2 / p
Ha nincs szükség a számjegyek számának megadására, és mindig az első tizedesjegyre kerekít, használhat egy egyszerűbb formát.
my_round_int = lambda x: int((x * 2 + 1) // 2)
Ha precíznek kell lennie, biztonságosabb a tizedesjegyek használata.
A következők csak tájékoztató jellegűek.
A tizedesjegyeket tetszőleges számú számjegyre kerekítheti.
print(int(my_round(f))) # 123 print(my_round_int(f)) # 123 print(my_round(f, 1)) # 123.5 print(my_round(f, 2)) # 123.46
A kerekítéssel ellentétben a 0,5 az általános kerekítésnek megfelelően 1 lesz.
print(int(my_round(0.4))) print(int(my_round(0.5))) print(int(my_round(0.6))) # 0 # 1 # 1
Egész számok kerekítése tetszőleges számú számjegyre
i = 99518 print(int(my_round(i, -1))) # 99520 print(int(my_round(i, -2))) # 99500 print(int(my_round(i, -3))) # 100000
A kerekítéssel ellentétben az 5-ből 10 lesz a szokásos kerekítés szerint.
print(int(my_round(4, -1))) print(int(my_round(5, -1))) print(int(my_round(6, -1))) # 0 # 10 # 10
Megjegyzés: Negatív értékek esetén
A fenti példafüggvényben a -0,5 0-ra van kerekítve.
print(int(my_round(-0.4))) print(int(my_round(-0.5))) print(int(my_round(-0.6))) # 0 # 0 # -1
A negatív értékek kerekítésére többféleképpen is gondolhatunk, de ha a -0,5-ből -1-et akarunk csinálni, akkor például a következőképpen módosíthatjuk a kerekítést
import math def my_round2(val, digit=0): p = 10 ** digit s = math.copysign(1, val) return (s * val * p * 2 + 1) // 2 / p * s print(int(my_round2(-0.4))) print(int(my_round2(-0.5))) print(int(my_round2(-0.6))) # 0 # -1 # -1