Bunder decimals lan integers ing Python karo “babak” lan “Decimal.quantize

Bisnis

Ing ngisor iki nerangake carane ngubengi nomer ing Python kanthi dibunderaké utawa dibunderaké menyang nomer genap. Angka kasebut dianggep minangka floating point float utawa integer int type.

  • fungsi built-in (contone ing basa pemrograman):round()
    • Bunder desimal menyang nomer apa wae.
    • Bunder ongko dadi nomer apa wae.
    • babak () babak kanggo nomer malah, ora kanggo dibunderaké umum
  • perpustakaan standardecimalquantize()
    • DecimalNggawe obyek
    • Dibunderaké desimal menyang nomer apa wae lan dibunderaké dadi nomer genap
    • Bunder saka integer kanggo nomer digit lan dibunderaké kanggo nomer genap
  • Netepake fungsi anyar
    • Bunder desimal menyang nomer apa wae.
    • Bunder ongko dadi nomer apa wae
    • Cathetan: Kanggo nilai negatif

Elinga yen, minangka kasebut ing ndhuwur, dibangun ing fungsi babak ora dibunderaké umum, nanging dibunderaké kanggo nomer malah. Deleng ing ngisor iki kanggo rincian.

fungsi built-in (contone ing basa pemrograman):round()

Round () kasedhiya minangka fungsi dibangun ing. Bisa digunakake tanpa ngimpor modul apa wae.

Argumentasi pisanan minangka nomer asli, lan argumen kapindho yaiku jumlah digit (pira digit sing kudu dibunderake).

Bunder desimal menyang nomer apa wae.

Ing ngisor iki minangka conto pangolahan kanggo jinis floating-point float.

Yen argumen kapindho diilangi, dibunderaké dadi integer. Jinis kasebut uga dadi jinis integer integer.

f = 123.456

print(round(f))
# 123

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

Yen argumen kapindho ditemtokake, bakal ngasilake jinis floating-point float.

Yen integer positif ditemtokake, panggonan desimal ditemtokake; yen integer negatif kasebut, panggonan integer kasebut. -1 babak kanggo sepuluh paling cedhak, -2 babak kanggo atus paling cedhak, lan 0 babak kanggo integer (panggonan pisanan), nanging ngasilake jinis float, ora kaya nalika ilang.

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

Bunder ongko dadi nomer apa wae.

Ing ngisor iki minangka conto pangolahan kanggo jinis integer integer.

Yen argumen kapindho diilangi, utawa yen 0 utawa integer positif ditemtokake, nilai asli bakal bali. Yen integer negatif ditemtokake, dibunderaké menyang digit integer sing cocog. Ing kasus loro, jinis integer int bali.

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

babak () babak kanggo nomer malah, ora kanggo dibunderaké umum

Elinga yen dibunderaké karo dibangun ing babak () fungsi ing Python 3 babak kanggo nomer malah, ora kanggo dibunderaké umum.

Kaya sing ditulis ing dokumentasi resmi, 0,5 dibunderaké dadi 0, 5 dibunderaké dadi 0, lan saterusé.

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

Dhéfinisi pembulatan menyang angka genap kaya ing ngisor iki.

Yen pecahan kurang saka 0,5, bunder mudhun; yen pecahan luwih saka 0,5, bunder munggah; yen bagian sekedhik persis 0,5, dibunderaké munggah menyang nomer malah antarane dibunderaké mudhun lan dibunderaké munggah.
Rounding – Wikipedia

0,5 ora tansah dipotong.

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

Ing sawetara kasus, definisi dibunderaké menyang nomer malah ora ditrapake kanggo proses sawise rong panggonan desimal.

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

Iki amarga kasunyatan sing desimal ora bisa diwakili persis minangka angka floating point, kaya sing kasebut ing dokumentasi resmi.

Prilaku babak () kanggo nomer floating titik bisa kaget sampeyan:Contone, babak (2,675, 2) bakal menehi 2,67 tinimbang 2,68 kaya samesthine. Iki dudu bug.:Iki minangka asil saka kasunyatan sing paling desimal ora bisa diwakili persis karo nomer floating point.
round() — Built-in Functions — Python 3.10.2 Documentation

Yen sampeyan pengin entuk pembulatan umum utawa pembulatan desimal sing akurat nganti nomer genap, sampeyan bisa nggunakake jumlah desimal perpustakaan standar (diterangake ing ngisor iki) utawa nemtokake fungsi anyar.

Uga Wigati sing babak () ing Python 2 ora dibunderaké menyang nomer malah, nanging dibunderaké.

quantize () saka desimal perpustakaan standar

Modul desimal perpustakaan standar bisa digunakake kanggo nangani angka floating point desimal sing tepat.

Nggunakake cara quantize () modul desimal, iku bisa kanggo babak nomer kanthi nemtokake mode dibunderaké.

Nilai-nilai sing disetel kanggo pembulatan argumen metode quantize () nduweni makna ing ngisor iki.

  • ROUND_HALF_UP:Pembulatan umum
  • ROUND_HALF_EVEN:Dibunderaké menyang nomer genap

Modul desimal minangka perpustakaan standar, mula ora mbutuhake instalasi tambahan, nanging ngimpor perlu.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Nggawe obyek Decimal

Decimal () bisa digunakake kanggo nggawe obyek saka jinis Decimal.

Yen sampeyan nemtokake jinis float minangka argumen, sampeyan bisa ndeleng apa sing dianggep bener.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

Minangka ditampilake ing conto, 0,05 ora dianggep persis 0,05. Iki alesan ngapa fungsi dibangun ing babak () diterangake ing ndhuwur dibunderaké menyang Nilai beda saka samesthine kanggo nilai desimal kalebu 0,05 ing conto.

Wiwit 0,5 minangka setengah (-1 daya saka 2), bisa ditulis kanthi tepat ing notasi biner.

print(Decimal(0.5))
# 0.5

Yen sampeyan nemtokake jinis string str tinimbang jinis float, iku bakal dianggep minangka jinis Decimal saka nilai pas.

print(Decimal('0.05'))
# 0.05

Dibunderaké desimal menyang nomer apa wae lan dibunderaké dadi nomer genap

Nelpon quantize () saka obyek saka jinis Decimal kanggo babak mati Nilai.

Argumentasi pisanan saka quantize () yaiku string kanthi jumlah digit sing padha karo jumlah digit sing pengin ditemokake, kayata ‘0.1’ utawa ‘0.01’.

Kajaba iku, argumen ROUNDING nemtokake mode rounding; yen ROUND_HALF_UP ditemtokake, dibunderaké umum digunakake.

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

Boten kados babak fungsi dibangun ing (), 0,5 dibunderaké kanggo 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

Yen argumen dibunderaké disetel kanggo ROUND_HALF_EVEN, dibunderaké dileksanakake kanggo nomer malah minangka ing dibangun ing fungsi babak ().

Kaya kasebut ing ndhuwur, yen floating-point jinis float ditemtokake minangka argumen saka Decimal (), dianggep minangka obyek Decimal karo nilai sing padha karo nilai nyata saka jinis float, supaya asil nggunakake quantize () cara bakal beda saka apa samesthine, kaya sing dibangun ing babak fungsi ().

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

Yen argumen saka Decimal () ditemtokake minangka senar saka jinis str, dianggep minangka obyek Decimal persis nilai sing, supaya asil kaya samesthine.

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

Wiwit 0,5 bisa ditangani kanthi bener dening jinis float, ora ana masalah kanggo nemtokake jinis float minangka argumen Decimal () nalika dibunderaké menyang integer, nanging luwih aman kanggo nemtokake jinis str string nalika dibunderaké menyang panggonan desimal.

Contone, 2.675 bener 2.67499 …. ing jinis float. Mulane, yen sampeyan pengin ngubengi rong panggonan desimal, sampeyan kudu nemtokake string menyang Decimal (), yen ora, asil bakal beda saka asil samesthine, yen sampeyan muter menyang nomer wutuh paling cedhak (ROUND_HALF_UP) utawa menyang nomer genap (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

Elinga yen cara quantize () ngasilake nomer jinis Decimal, supaya yen sampeyan pengin operate ing nomer jinis ngambang, sampeyan kudu ngowahi menyang jinis ngambang nggunakake float (), yen ora ana kesalahan.

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

Bunder saka integer kanggo nomer digit lan dibunderaké kanggo nomer genap

Yen sampeyan pengin dibunderake menyang digit integer, nemtokake kaya ’10’ minangka argumen pisanan ora bakal menehi asil sing dikarepake.

i = 99518

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

Iki amarga quantize () nindakake pembulatan miturut eksponen obyek Decimal, nanging eksponen Decimal (’10’) yaiku 0, dudu 1.

Sampeyan bisa nemtokake eksponen sembarang kanthi nggunakake E minangka string eksponen (contone, ‘1E1’). Eksponen eksponen bisa dicenthang ing metode 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)

Minangka, asil bakal ing cathetan eksponensial nggunakake E. Yen sampeyan pengin nggunakake notasi normal, utawa yen sampeyan pengin operate karo integer jinis int sawise dibunderaké, nggunakake int () kanggo ngowahi asil.

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

Yen pembulatan argumen disetel dadi ROUND_HALF_UP, pembulatan umum bakal kedadeyan, contone, 5 bakal dibunderake dadi 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

Mesthi, ora ana masalah yen sampeyan nemtokake minangka senar.

Netepake fungsi anyar

Cara nggunakake modul desimal akurat lan aman, nanging yen sampeyan ora nyaman karo jinis konversi, sampeyan bisa netepake fungsi anyar kanggo entuk pambulatan umum.

Ana akeh cara kanggo nindakake iki, contone, fungsi ing ngisor iki.

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

Yen sampeyan ora perlu kanggo nemtokake nomer digit lan tansah babak menyang panggonan desimal pisanan, sampeyan bisa nggunakake wangun prasaja.

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

Yen sampeyan kudu akurat, luwih aman nggunakake desimal.

Ing ngisor iki mung kanggo referensi.

Bunder desimal menyang nomer apa wae.

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

Ora kaya babak, 0,5 dadi 1 minangka saben babak umum.

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

Bunder ongko dadi nomer apa wae

i = 99518

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

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

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

Ora kaya babak, 5 dadi 10 minangka saben babak umum.

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

Cathetan: Kanggo nilai negatif

Ing conto fungsi ing ndhuwur, -0.5 dibunderaké dadi 0.

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

Ana macem-macem cara mikir babagan pembulatan kanggo nilai negatif, nanging yen sampeyan pengin nggawe -0,5 dadi -1, sampeyan bisa ngowahi kaya ing ngisor iki, contone.

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