Pythoni kümnend- ja täisarvude ümardamine funktsioonidega “round” ja “Decimal.quantize”.

Äri

Järgnevalt selgitatakse, kuidas Pythonis numbreid ümardada, ümardades või ümardades paariliseks arvuks. Eeldatakse, et arvud on ujukoma- või täisarvu int-tüüpi.

  • sisseehitatud funktsioon (nt programmeerimiskeeles): round()
    • Ümardage kümnendarvud suvalise arvu numbriteni.
    • Ümardada täisarvud suvalise arvu numbriteni.
    • round() ümardab paarisarvuni, mitte ühisele ümardamisele.
  • standardne raamatukogudecimal quantize()
    • DecimalObjekti loomine
    • Kümnendkohtade ümardamine suvalise arvu numbriteni ja ümardamine paarisarvudeks
    • täisarvude ümardamine suvalise arvu numbriteni ja ümardamine paarisarvudeks
  • Määrake uus funktsioon
    • Ümardage kümnendkohad suvalise arvu numbriteni.
    • Ümardada täisarvud suvalise arvu numbriteni
    • Märkus: negatiivsete väärtuste puhul

Pange tähele, et nagu eespool mainitud, ei ole sisseehitatud funktsioon round üldine ümardamine, vaid ümardamine paarilise arvuni. Vt allpool üksikasju.

sisseehitatud funktsioon (nt programmeerimiskeeles): round()

Round() on sisseehitatud funktsioon. Seda saab kasutada ilma mooduleid importimata.

Esimene argument on algne arv ja teine argument on numbrite arv (mitu kohta ümardada).

Ümardage kümnendarvud suvalise arvu numbriteni.

Järgnevalt on toodud näide ujukoma-tüüpi ujukoma töötlemise kohta.

Kui teine argument jäetakse ära, ümardatakse see täisarvuks. Tüübiks saab samuti täisarv int.

f = 123.456

print(round(f))
# 123

print(type(round(f)))
# <class 'int'>

Kui teine argument on määratud, tagastab see ujukoma-tüüpi ujukoma.

Kui on määratud positiivne täisarv, määratakse kümnendkoht; kui on määratud negatiivne täisarv, määratakse täisarvu koht. -1 ümardab lähima kümnendikuni, -2 ümardab lähima sajandikuni ja 0 ümardab täisarvuks (esimene koht), kuid tagastab float-tüüpi, erinevalt sellest, kui see jäetakse välja.

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

Ümardada täisarvud suvalise arvu numbriteni.

Järgnevalt on toodud näide täisarvu int tüübi töötlemisest.

Kui teine argument jäetakse ära või kui on määratud 0 või positiivne täisarv, tagastatakse algväärtus sellisena, nagu see on. Kui on määratud negatiivne täisarv, ümardatakse see vastava täisarvuni. Mõlemal juhul tagastatakse täisarvu tüüpi int.

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() ümardab paarisarvuni, mitte ühisele ümardamisele.

Pange tähele, et Python 3 sisseehitatud funktsiooniga round() ümardamine ümardab paarilisele arvule, mitte üldisele ümardamisele.

Ametlikus dokumentatsioonis on kirjas, et 0,5 on ümardatud 0-ks, 5 on ümardatud 0-ks jne.

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

Punktile ümardamise määratlus on järgmine.

Kui murdosa on väiksem kui 0,5, ümardage see alla; kui murdosa on suurem kui 0,5, ümardage see ülespoole; kui murdosa on täpselt 0,5, ümardage see ülespoole ümardamise ja ülespoole ümardamise vahelisele paarilisele arvule.
Rounding – Wikipedia

0,5 ei ole alati kärbitud.

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

Mõnel juhul ei kehti ümardamise määratlus isegi mitte kahe kümnendkoha järgse töötlemise puhul.

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

Selle põhjuseks on asjaolu, et kümnendkohti ei saa esitada täpselt ujukomaarvudena, nagu on kirjas ametlikus dokumentatsioonis.

Round() käitumine ujukomaarvude puhul võib teid üllatada.:Näiteks round(2,675, 2) annab tulemuseks 2,67, mitte 2,68, nagu oodatud. See ei ole viga.:See tuleneb asjaolust, et enamikku kümnendarvudest ei saa täpselt esitada ujukomaarvudega.
round() — Built-in Functions — Python 3.10.2 Documentation

Kui soovite saavutada üldist ümardamist või kümnendkohtade täpset ümardamist paarisarvudeks, võite kasutada standardraamatukogu kümnendkohtade kvantifitseerimist (kirjeldatud allpool) või defineerida uue funktsiooni.

Pange ka tähele, et Python 2s ei ole ümardamine ümmarguseks, vaid ümardamine.

kvantize() standardraamatukogu decimal

Standardraamatukogu kümnendmoodulit saab kasutada täpsete kümnendkeskmise ujukomaarvude käsitlemiseks.

Kasutades kümnendmooduli meetodit quantize(), on võimalik numbreid ümardada, määrates ümardamisrežiimi.

Meetodi quantize() argumendi ümardamise väärtustel on vastavalt järgmised tähendused.

  • ROUND_HALF_UP:Üldine ümardamine
  • ROUND_HALF_EVEN:Ümardamine paarisnumbriliste arvudeni

Detsimaalmoodul on standardne raamatukogu, nii et lisainstallatsiooni ei ole vaja teha, kuid importimine on vajalik.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Detsimaalse objekti loomine

Decimal() saab kasutada Decimal tüüpi objektide loomiseks.

Kui annate argumendiks float-tüübi, näete, millisena seda väärtust tegelikult käsitletakse.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

print(type(Decimal(0.05)))
# <class 'decimal.Decimal'>

Nagu näites näidatud, ei käsitleta 0,05 täpselt 0,05-na. See on põhjus, miks eespool kirjeldatud sisseehitatud funktsioon round() ümardab kümnendväärtuste, sealhulgas näites esitatud 0,05, puhul oodatust erineva väärtuse.

Kuna 0,5 on pool (-1 võimsus 2), saab seda täpselt väljendada binaarses kirjutusviisis.

print(Decimal(0.5))
# 0.5

Kui annate float-tüübi asemel string-tüübi str, käsitletakse seda täpse väärtuse Decimal-tüübina.

print(Decimal('0.05'))
# 0.05

Kümnendkohtade ümardamine suvalise arvu numbriteni ja ümardamine paarisarvudeks

Kutsuge kvantifitseeri() tüüpi Decimal objektist, et ümardada väärtus.

Quantize() esimene argument on string, millel on sama arv numbreid, kui on soovitud numbrite arv, näiteks '0.1' või '0.01'.

Lisaks määrab argument ROUNDING ümardamisrežiimi; kui on määratud ROUND_HALF_UP, kasutatakse üldist ümardamist.

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

Erinevalt sisseehitatud funktsioonist round() ümardatakse 0,5 arvuks 1.

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

Kui argumendiks ümardamine on seatud ROUND_HALF_EVEN, ümardatakse paariliste arvudeni nagu sisseehitatud funktsioonis round().

Nagu eespool mainitud, kui Decimal() argumendiks on määratud ujukoma-tüüpi float, käsitletakse seda kui Decimal-objekti, mille väärtus on võrdne float-tüübi tegeliku väärtusega, nii et meetodi quantize() kasutamise tulemus erineb oodatust, nagu ka sisseehitatud funktsiooni round() tulemus.

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

Kui Decimal() argument on määratud str-tüüpi stringina, käsitletakse seda täpselt selle väärtusega Decimal-objektina, nii et tulemus on ootuspärane.

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

Kuna 0,5 saab korrektselt käsitleda float-tüüpi, ei ole probleemiks, kui täisarvuks ümardamise korral määratakse Decimal() argumendiks float-tüüpi, kuid kümnendkohani ümardamisel on turvalisem määrata string str-tüüpi.

Näiteks 2,675 on tegelikult 2,67499…. float-tüüpi. Seega, kui soovite ümardada kahe kümnendkohani, peate Decimal() funktsioonile esitama stringi, sest vastasel juhul erineb tulemus oodatavast tulemusest, olenemata sellest, kas ümardate lähima täisarvuni (ROUND_HALF_UP) või paarilise arvuni (ROUND_HALF_EVEN).

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

Pange tähele, et meetod quantize() tagastab kümnenditüüpi arvu, nii et kui soovite töötada float-tüüpi arvuga, tuleb see teisendada float-tüüpi arvuks, kasutades funktsiooni float(), vastasel juhul tekib viga.

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

täisarvude ümardamine suvalise arvu numbriteni ja ümardamine paarisarvudeks

Kui soovite ümardada täisarvuni, ei anna esimese argumendina näiteks '10' soovitud tulemust.

i = 99518

print(Decimal(i).quantize(Decimal('10'), rounding=ROUND_HALF_UP))
# 99518

Selle põhjuseks on see, et quantize() ümardab vastavalt Decimal-objekti eksponendile, kuid Decimal('10') eksponent on 0, mitte 1.

Saate määrata suvalise eksponendi, kasutades eksponendijada E (nt '1E1'). Eksponendi eksponenti saab kontrollida meetodis as_tuple.

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)

Nagu see on, on tulemus eksponentsiaalses märkimises, kasutades E. Kui soovite kasutada tavalist märkimist või kui soovite pärast ümardamist töötada täisarvu int-tüübiga, kasutage tulemuse teisendamiseks funktsiooni int().

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

Kui argumendiks ümardamine on seatud ROUND_HALF_UP, toimub üldine ümardamine, nt 5 ümardatakse 10-le.

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

Loomulikult ei ole probleemi, kui määrate selle stringina.

Määrake uus funktsioon

Kümnendmooduli kasutamise meetod on täpne ja turvaline, kuid kui te ei tunne end mugavalt tüübi teisendamisega, võite defineerida uue funktsiooni, et saavutada üldine ümardamine.

Selleks on palju võimalikke viise, näiteks järgmine funktsioon.

def my_round(val, digit=0):
    p = 10 ** digit
    return (val * p * 2 + 1) // 2 / p

Kui te ei pea täpsustama numbrite arvu ja ümardate alati esimese kümnendkohani, võite kasutada lihtsamat vormi.

my_round_int = lambda x: int((x * 2 + 1) // 2)

Kui on vaja olla täpne, on turvalisem kasutada kümnendmurdeid.

Alljärgnev on ainult viitena.

Ümardage kümnendkohad suvalise arvu numbriteni.

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

Erinevalt ümardamisest muutub 0,5 vastavalt üldisele ümardamisele 1.

print(int(my_round(0.4)))
print(int(my_round(0.5)))
print(int(my_round(0.6)))
# 0
# 1
# 1

Ümardada täisarvud suvalise arvu numbriteni

i = 99518

print(int(my_round(i, -1)))
# 99520

print(int(my_round(i, -2)))
# 99500

print(int(my_round(i, -3)))
# 100000

Erinevalt ümardamisest muutub 5 tavapäraste ümardamiste kohaselt 10-ks.

print(int(my_round(4, -1)))
print(int(my_round(5, -1)))
print(int(my_round(6, -1)))
# 0
# 10
# 10

Märkus: negatiivsete väärtuste puhul

Ülaltoodud näitefunktsioonis on -0,5 ümardatud 0-ks.

print(int(my_round(-0.4)))
print(int(my_round(-0.5)))
print(int(my_round(-0.6)))
# 0
# 0
# -1

Negatiivsete väärtuste ümardamisel on erinevaid mõtlemisviise, kuid kui soovite teha -0,5-st -1, saate seda muuta näiteks järgmiselt.

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
Copied title and URL