Desimaalien ja kokonaislukujen pyöristäminen Pythonissa ”round” ja ”Decimal.quantize” -toiminnoilla.

liiketoiminta

Seuraavassa kerrotaan, miten Pythonissa pyöristetään lukuja pyöristämällä tai pyöristämällä parilliseen lukuun. Lukujen oletetaan olevan liukulukutyyppiä float tai kokonaislukutyyppiä int.

  • sisäänrakennettu funktio (esim. ohjelmointikielessä): round()
    • Pyöristää desimaaliluvut mihin tahansa numerolukuun.
    • Pyöristää kokonaisluvut mihin tahansa numeromäärään.
    • round() pyöristää parilliseen lukuun, ei yhteiseen pyöristykseen.
  • standardikirjastodecimal quantize()
    • DecimalObjektin luominen
    • Desimaalilukujen pyöristäminen mihin tahansa numerolukuun ja pyöristäminen parillisiin lukuihin.
    • Kokonaislukujen pyöristäminen mihin tahansa numerolukuun ja pyöristäminen parillisiin lukuihin.
  • Määritä uusi funktio
    • Pyöristää desimaaliluvut mihin tahansa numerolukuun.
    • Kokonaislukujen pyöristäminen mihin tahansa numeromäärään
    • Huomautus: Negatiivisten arvojen osalta

Huomaa, että kuten edellä mainittiin, sisäänrakennettu funktio round ei ole yleinen pyöristys, vaan pyöristys parilliseen lukuun. Katso lisätietoja jäljempänä.

sisäänrakennettu funktio (esim. ohjelmointikielessä): round()

Round() on sisäänrakennettu funktio. Sitä voidaan käyttää ilman moduulien tuontia.

Ensimmäinen argumentti on alkuperäinen luku ja toinen argumentti on numeroiden määrä (kuinka moneksi numeroksi pyöristetään).

Pyöristää desimaaliluvut mihin tahansa numerolukuun.

Seuraavassa on esimerkki liukulukutyypin float käsittelystä.

Jos toinen argumentti jätetään pois, se pyöristetään kokonaisluvuksi. Tyypistä tulee myös kokonaislukutyyppi int.

f = 123.456

print(round(f))
# 123

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

Jos toinen argumentti on määritetty, se palauttaa liukulukutyypin.

Jos määritetään positiivinen kokonaisluku, määritetään desimaalipiste; jos määritetään negatiivinen kokonaisluku, määritetään kokonaislukupiste. -1 pyöristää lähimpään kymmenesosaan, -2 pyöristää lähimpään sadasosaan ja 0 pyöristää kokonaislukuun (ensimmäiseen paikkaan), mutta palauttaa float-tyypin, toisin kuin jos se jätetään pois.

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

Pyöristää kokonaisluvut mihin tahansa numeromäärään.

Seuraavassa on esimerkki kokonaislukutyypin int käsittelystä.

Jos toinen argumentti jätetään pois tai jos määritetään 0 tai positiivinen kokonaisluku, alkuperäinen arvo palautetaan sellaisenaan. Jos annetaan negatiivinen kokonaisluku, se pyöristetään vastaavaan kokonaislukuun. Molemmissa tapauksissa palautetaan kokonaislukutyyppinen 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() pyöristää parilliseen lukuun, ei yhteiseen pyöristykseen.

Huomaa, että Python 3:n sisäänrakennetulla round()-funktiolla pyöristetään parilliseen lukuun, ei yleiseen pyöristykseen.

Virallisen dokumentaation mukaan 0,5 pyöristetään 0:ksi, 5 pyöristetään 0:ksi ja niin edelleen.

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

Pyöristäminen parilliseksi luvuksi määritellään seuraavasti.

Jos murtoluku on pienempi kuin 0,5, pyöristä se alaspäin; jos murtoluku on suurempi kuin 0,5, pyöristä se ylöspäin; jos murtoluku on tasan 0,5, pyöristä se ylöspäin pyöristämisen ja alaspäin pyöristämisen välillä olevaan parilliseen lukuun.
Rounding – Wikipedia

0,5 ei ole aina typistetty.

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

Joissakin tapauksissa määritelmä pyöristämisestä parilliseen lukuun ei koske edes käsittelyä kahden desimaalin jälkeen.

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

Tämä johtuu siitä, että desimaalilukuja ei voida esittää täsmälleen liukulukuina, kuten virallisessa dokumentaatiossa todetaan.

Round():n käyttäytyminen liukuluvuille voi yllättää sinut.:Esimerkiksi round(2.675, 2) antaa tulokseksi 2.67 eikä 2.68, kuten odotettiin. Tämä ei ole virhe.:Tämä johtuu siitä, että useimpia desimaalilukuja ei voida esittää tarkasti liukuluvuilla.
round() — Built-in Functions — Python 3.10.2 Documentation

Jos haluat saada aikaan yleisen pyöristyksen tai tarkan pyöristyksen desimaaliluvuista parillisiin lukuihin, voit käyttää standardikirjaston decimal quantize -funktiota (kuvattu alla) tai määritellä uuden funktion.

Huomaa myös, että Python 2:ssa round() ei pyöristä parilliseen lukuun, vaan pyöristää.

kvantisoi() standardikirjastossa decimal

Standardikirjaston decimal-moduulia voidaan käyttää tarkkojen desimaalisten liukulukujen käsittelyyn.

Desimaalimoduulin quantize()-metodilla on mahdollista pyöristää lukuja määrittämällä pyöristystapa.

Kvantisoi()-menetelmän argumentin pyöristys asetetuilla arvoilla on seuraavat merkitykset.

  • ROUND_HALF_UP:Yleinen pyöristys
  • ROUND_HALF_EVEN:Pyöristäminen parillisiin lukuihin

Decimal-moduuli on standardikirjasto, joten lisäasennusta ei tarvita, mutta tuonti on välttämätöntä.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Desimaaliobjektin luominen

Decimal() -toimintoa voidaan käyttää Decimal-tyyppisten objektien luomiseen.

Jos annat argumenttina float-tyypin, näet, miten arvoa todellisuudessa käsitellään.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

Kuten esimerkissä näkyy, 0,05:tä ei käsitellä täsmälleen 0,05:nä. Tämä on syy siihen, miksi edellä kuvattu sisäänrakennettu funktio round() pyöristää eri arvoon kuin odotettiin desimaaliarvoille, joihin esimerkissä sisältyi 0,05.

Koska 0,5 on puolet (-1 potenssi 2:sta), se voidaan ilmaista täsmälleen binäärimuodossa.

print(Decimal(0.5))
# 0.5

Jos määrität merkkijonotyypin str float-tyypin sijasta, sitä käsitellään täsmällisen arvon Decimal-tyyppinä.

print(Decimal('0.05'))
# 0.05

Desimaalilukujen pyöristäminen mihin tahansa numerolukuun ja pyöristäminen parillisiin lukuihin.

Kutsu quantize() -toimintoa Decimal-tyyppisestä objektista arvon pyöristämiseksi.

Quantize():n ensimmäinen argumentti on merkkijono, jossa on sama määrä numeroita kuin haluamasi numeroiden määrä, esimerkiksi '0.1' tai '0.01'.

Lisäksi argumentti ROUNDING määrittää pyöristystavan; jos ROUND_HALF_UP on määritetty, käytetään yleistä pyöristystä.

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

Toisin kuin sisäänrakennettu funktio round(), 0,5 pyöristetään arvoon 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

Jos argumentin pyöristys arvoksi asetetaan ROUND_HALF_EVEN, pyöristys suoritetaan parillisiin lukuihin kuten sisäänrakennetussa funktiossa round().

Kuten edellä mainittiin, jos Decimal()-metodin argumentiksi määritetään liukulukutyyppinen liukuluku, sitä käsitellään Decimal-oliona, jonka arvo vastaa liukulukutyypin todellista arvoa, joten kvantisoi()-metodin käytön tulos poikkeaa odotetusta, aivan kuten sisäänrakennettu funktio 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

Jos Decimal():n argumentti on määritetty merkkijonona, jonka tyyppi on str, sitä käsitellään Decimal-oliona, jonka arvo on täsmälleen sama, joten tulos on odotusten mukainen.

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

Koska 0,5 voidaan käsitellä oikein float-tyypillä, ei ole ongelma määrittää float-tyyppiä Decimal():n argumentiksi, kun pyöristetään kokonaisluvuksi, mutta on turvallisempaa määrittää merkkijonon str-tyyppi, kun pyöristetään desimaalilukuun.

Esimerkiksi 2,675 on itse asiassa 2,67499…. float-tyyppisenä. Jos siis haluat pyöristää kahteen desimaaliin, sinun on määritettävä merkkijono Decimal()-toiminnolle, muuten tulos poikkeaa odotetusta tuloksesta riippumatta siitä, pyöristätkö lähimpään kokonaislukuun (ROUND_HALF_UP) vai parilliseen lukuun (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

Huomaa, että quantize()-metodi palauttaa Decimal-tyyppisen luvun, joten jos haluat käyttää float-tyyppistä lukua, sinun on muunnettava se float-tyypiksi käyttämällä float()-toimintoa, muuten tapahtuu virhe.

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

Kokonaislukujen pyöristäminen mihin tahansa numerolukuun ja pyöristäminen parillisiin lukuihin.

Jos haluat pyöristää kokonaislukuun, jos annat ensimmäisenä argumenttina esimerkiksi '10', et saa haluttua tulosta.

i = 99518

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

Tämä johtuu siitä, että quantize() suorittaa pyöristyksen Decimal-olion eksponentin mukaan, mutta Decimal('10')-olion eksponentti on 0, ei 1.

Voit määrittää mielivaltaisen eksponentin käyttämällä E:tä eksponenttijonona (esim. '1E1'). Eksponentin eksponentti voidaan tarkistaa as_tuple-metodissa.

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)

Jos haluat käyttää normaalia merkintätapaa tai jos haluat käyttää kokonaislukutyyppiä int pyöristyksen jälkeen, käytä tuloksen muuntamiseen int()-toimintoa.

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

Jos argumentin pyöristys arvoksi on asetettu ROUND_HALF_UP, suoritetaan yleinen pyöristys, esimerkiksi 5 pyöristetään arvoon 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

Ongelmia ei tietenkään ole, jos määrität sen merkkijonona.

Määritä uusi funktio

Menetelmä, jossa käytetään desimaalimoduulia, on tarkka ja turvallinen, mutta jos tyyppimuunnos ei tunnu mukavalta, voit määritellä uuden funktion yleistä pyöristystä varten.

Tähän on monia mahdollisia tapoja, esimerkiksi seuraava funktio.

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

Jos sinun ei tarvitse määrittää numeroiden lukumäärää ja pyöristät aina ensimmäiseen desimaaliin, voit käyttää yksinkertaisempaa muotoa.

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

Jos haluat olla tarkka, on turvallisempaa käyttää desimaalilukua.

Seuraavat tiedot ovat vain viitteellisiä.

Pyöristää desimaaliluvut mihin tahansa numerolukuun.

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

Toisin kuin kierroksella, 0,5:stä tulee 1 yleisen pyöristyksen mukaisesti.

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

Kokonaislukujen pyöristäminen mihin tahansa numeromäärään

i = 99518

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

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

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

Toisin kuin pyöristyksessä, 5:stä tulee 10 yleisen pyöristyksen mukaisesti.

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

Huomautus: Negatiivisten arvojen osalta

Yllä olevassa esimerkkifunktiossa -0,5 pyöristetään arvoon 0.

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

Negatiivisten arvojen pyöristämistä voidaan ajatella eri tavoin, mutta jos haluat tehdä -0,5:stä -1:n, voit muuttaa sitä esimerkiksi seuraavasti

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