Námundar tugabrot og heiltölur í Python með „round“ og „Decimal.quantize

Viðskipti

Eftirfarandi útskýrir hvernig á að námunda tölur í Python með því að námundun eða námundun í slétta tölu. Gert er ráð fyrir að tölurnar séu af floating point float eða heiltölu int gerð.

  • innbyggð aðgerð (t.d. í forritunarmáli):round()
    • Námundaðu aukastafi að hvaða tölu sem er.
    • Námundaðu heilar tölur að hvaða tölu sem er.
    • round() námundar í slétta tölu, ekki að algengri námundun
  • staðlað bókasafndecimalquantize()
    • DecimalAð búa til hlut
    • Námundun aukastafa í hvaða tölu sem er og námundun í sléttar tölur
    • Námundun heiltalna að hvaða tölu sem er og námundun í sléttar tölur
  • Skilgreindu nýja aðgerð
    • Runda aukastafa af í hvaða fjölda tölustafa sem er.
    • Námundaðu heilar tölur að hvaða tölu sem er
    • Athugið: Fyrir neikvæð gildi

Athugið að eins og fram kemur hér að ofan er innbyggða fallumferðin ekki almenn námundun, heldur námundun í slétta tölu. Sjá nánar hér að neðan.

innbyggð aðgerð (t.d. í forritunarmáli):round()

Round() er veitt sem innbyggð aðgerð. Það er hægt að nota án þess að flytja inn neinar einingar.

Fyrsta röksemdin er upphaflega talan og önnur rökin eru tölustafafjöldinn (hversu margir tölustafir á að námunda að).

Námundaðu aukastafi að hvaða tölu sem er.

Eftirfarandi er dæmi um vinnslu fyrir flotategundina.

Ef seinni röksemdinni er sleppt er hún námunduð í heila tölu. Tegundin verður líka að heiltölu int gerð.

f = 123.456

print(round(f))
# 123

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

Ef önnur rökin eru tilgreind, skilar hún fljótandi tegund.

Ef jákvæð heil tala er tilgreind er aukastafurinn tilgreindur; ef neikvæð heil tala er tilgreind er heiltölustaðurinn tilgreindur. -1 umferð í næsta tíunda, -2 umferðir í næsta hundraðasta og 0 umferð í heila tölu (fyrsta sætið), en skilar flotgerð, ólíkt því þegar henni er sleppt.

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

Námundaðu heilar tölur að hvaða tölu sem er.

Eftirfarandi er dæmi um vinnslu fyrir heiltölu int gerð.

Ef seinni röksemdinni er sleppt, eða ef 0 eða jákvæð heil tala er tilgreind, er upprunalega gildinu skilað eins og það er. Ef neikvæð heil tala er tilgreind er hún námunduð að samsvarandi heiltölu. Í báðum tilfellum er heiltölu int gerð skilað.

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() námundar í slétta tölu, ekki að algengri námundun

Athugaðu að námundun með innbyggðu round() fallinu í Python 3 umferðum í slétta tölu, ekki í almenna námundun.

Eins og skrifað er í opinberu skjölunum er 0,5 námundað í 0, 5 er námundað í 0, og svo framvegis.

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

Skilgreiningin á námundun í slétta tölu er sem hér segir.

Ef brotið er minna en 0,5, námundaðu það niður; ef brotið er stærra en 0,5 skaltu hringja það upp; ef brotið er nákvæmlega 0,5, námundaðu það upp í sléttu töluna á milli þess að námundun niður og námundun upp.
Rounding – Wikipedia

0,5 er ekki alltaf stytt.

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

Í sumum tilfellum á skilgreiningin á námundun í slétta tölu ekki einu sinni við um vinnslu eftir tvo aukastafi.

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

Þetta er vegna þess að ekki er hægt að tákna tugastafi nákvæmlega sem flottölur, eins og fram kemur í opinberu skjölunum.

Hegðun round() fyrir flottölur gæti komið þér á óvart:Til dæmis mun round(2.675, 2) gefa þér 2.67 í stað 2.68 eins og búist var við. Þetta er ekki galli.:Þetta er afleiðing af þeirri staðreynd að ekki er hægt að tákna flesta tugastafi nákvæmlega með flottölum.
round() — Built-in Functions — Python 3.10.2 Documentation

Ef þú vilt ná almennri námundun eða nákvæmri námundun á tugabrotum í sléttar tölur, geturðu notað staðlaða tugafjölda safnsins (lýst hér að neðan) eða skilgreint nýja aðgerð.

Athugaðu líka að round() í Python 2 er ekki námundun í slétta tölu, heldur námundun.

quantize() af staðlaða aukastafi bókasafnsins

Hægt er að nota tugaeiningu staðlaða bókasafnsins til að meðhöndla nákvæmar tugabrotatölur.

Með því að nota quantize() aðferð tugaeiningarinnar er hægt að námunda tölur með því að tilgreina námundunarhaminn.

Stilltu gildin fyrir námundun rifrilda quantize() aðferðarinnar hafa eftirfarandi merkingu, í sömu röð.

  • ROUND_HALF_UP:Almenn námundun
  • ROUND_HALF_EVEN:Námundun í sléttar tölur

Tugaeiningin er venjulegt bókasafn, svo engin viðbótaruppsetning er nauðsynleg, en innflutningur er nauðsynlegur.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Að búa til aukastaf

Decimal() er hægt að nota til að búa til hluti af gerðinni Decimal.

Ef þú tilgreinir flotgerð sem rök geturðu séð hvað gildið er í raun meðhöndlað sem.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

Eins og sýnt er í dæminu er 0,05 ekki meðhöndlað sem nákvæmlega 0,05. Þetta er ástæðan fyrir því að innbyggða fallið round() sem lýst er hér að ofan námundaði að öðru gildi en búist var við fyrir aukastafagildi þar á meðal 0,05 í dæminu.

Þar sem 0,5 er hálft (-1 veldi af 2) er hægt að tjá það nákvæmlega í tvíundarskrift.

print(Decimal(0.5))
# 0.5

Ef þú tilgreinir strengsgerðina str í stað flotgerðarinnar, verður hún meðhöndluð sem tugategund fyrir nákvæmlega gildið.

print(Decimal('0.05'))
# 0.05

Námundun aukastafa í hvaða tölu sem er og námundun í sléttar tölur

Hringdu í quantize() úr hlut af gerðinni Decimal til að ná gildinu.

Fyrstu rökin fyrir quantize() er strengur með sama fjölda tölustafa og fjöldi tölustafa sem þú vilt finna, eins og ‘0.1’ eða ‘0.01’.

Að auki tilgreinir röksemdin ROUNDING námundunarhaminn; ef ROUND_HALF_UP er tilgreint er almenn námundun notuð.

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

Ólíkt innbyggðu fallinu round() er 0,5 námundað í 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

Ef námundun rifrilda er stillt á ROUND_HALF_EVEN, er námundun framkvæmd í sléttar tölur eins og í innbyggðu fallinu round().

Eins og nefnt er hér að ofan, ef fljótandi tegund af floti er tilgreind sem rök fyrir Decimal(), er hún meðhöndluð sem Decimal hlutur með gildi sem er jafnt og raunverulegu gildi flotgerðarinnar, sem er afleiðing af notkun quantize() aðferðin verður önnur en búist er við, rétt eins og innbyggða fallið round().

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

Ef rökstuðningur Decimal() er tilgreindur sem strengur af gerðinni str, er hann meðhöndlaður sem Decimal hlutur með nákvæmlega það gildi, þannig að niðurstaðan er eins og búist var við.

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

Þar sem hægt er að meðhöndla 0.5 rétt af flotgerðinni er ekkert vandamál að tilgreina flotgerðina sem röksemdafærslu Decimal() þegar námundað er að heiltölu, en öruggara er að tilgreina strengsgerðina str þegar námundað er að aukastaf.

Til dæmis er 2.675 í raun 2.67499…. í flotgerð. Þess vegna, ef þú vilt námunda að tveimur aukastöfum, verður þú að tilgreina streng í Decimal(), annars verður niðurstaðan önnur en væntanleg niðurstaða hvort sem þú námundar að næstu heilu tölu (ROUND_HALF_UP) eða í slétta tölu (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

Athugaðu að quantize() aðferðin skilar decimal tegundarnúmeri, þannig að ef þú vilt vinna á flottegundarnúmeri þarftu að umbreyta henni í flotgerð með því að nota float(), annars mun villa koma upp.

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

Námundun heiltalna að hvaða tölu sem er og námundun í sléttar tölur

Ef þú vilt námunda að heiltölu, mun það ekki gefa þér þá niðurstöðu sem þú vilt, ef þú tilgreinir eitthvað eins og ’10’ sem fyrstu röksemd.

i = 99518

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

Þetta er vegna þess að quantize() framkvæmir námundun í samræmi við veldisvísi tugahlutarins, en veldisvísir tugabrots(’10’) er 0, ekki 1.

Þú getur tilgreint handahófskennda veldisvísi með því að nota E sem veldisvísisstreng (t.d. ‘1E1’). Hægt er að athuga veldisvísisveldið í as_tuple aðferðinni.

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)

Eins og það er, verður niðurstaðan í veldisvísisnátnun með því að nota E. Ef þú vilt nota venjulega nótnaskrift, eða ef þú vilt vinna með heiltölu int gerð eftir námundun, notaðu int() til að umbreyta niðurstöðunni.

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

Ef námundun röksemda er stillt á ROUND_HALF_UP mun almenn námundun eiga sér stað, t.d. 5 verður námundað í 10.

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

Auðvitað er ekkert vandamál ef þú tilgreinir það sem streng.

Skilgreindu nýja aðgerð

Aðferðin við að nota tugaeininguna er nákvæm og örugg, en ef þú ert ekki sátt við tegundabreytingu geturðu skilgreint nýja aðgerð til að ná almennri námundun.

Það eru margar mögulegar leiðir til að gera þetta, til dæmis eftirfarandi aðgerð.

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

Ef ekki þarf að tilgreina fjölda tölustafa og alltaf námundað að fyrsta aukastaf er hægt að nota einfaldara form.

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

Ef þú þarft að vera nákvæmur er öruggara að nota aukastaf.

Eftirfarandi er eingöngu til viðmiðunar.

Runda aukastafa af í hvaða fjölda tölustafa sem er.

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

Ólíkt umferð verður 0,5 1 samkvæmt almennri námundun.

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

Námundaðu heilar tölur að hvaða tölu sem er

i = 99518

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

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

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

Ólíkt umferð verður 5 10 samkvæmt algengri námundun.

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

Athugið: Fyrir neikvæð gildi

Í dæmifallinu hér að ofan er -0,5 námundað að 0.

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

Það eru ýmsar leiðir til að hugsa um námundun fyrir neikvæð gildi, en ef þú vilt gera -0,5 í -1 geturðu breytt því á eftirfarandi hátt, td.

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