Membundarkan perpuluhan dan integer dalam Python dengan “bulat” dan “Decimal.quantize

Perniagaan

Berikut menerangkan cara untuk membundarkan nombor dalam Python dengan membundarkan atau membundarkan kepada nombor genap. Nombor-nombor tersebut diandaikan sebagai apungan titik terapung atau jenis integer int.

  • fungsi terbina dalam (cth. dalam bahasa pengaturcaraan):round()
    • Bundarkan perpuluhan kepada sebarang nombor digit.
    • Bundarkan integer kepada sebarang nombor digit.
    • round() membundarkan kepada nombor genap, bukan kepada pembundaran biasa
  • perpustakaan standarddecimalquantize()
    • DecimalMencipta objek
    • Membundarkan perpuluhan kepada sebarang nombor digit dan membundarkan kepada nombor genap
    • Membundarkan integer kepada sebarang nombor digit dan membundarkan kepada nombor genap
  • Tentukan fungsi baharu
    • Bundarkan perpuluhan kepada sebarang nombor digit.
    • Bundarkan integer kepada sebarang nombor digit
    • Nota: Untuk nilai negatif

Ambil perhatian bahawa, seperti yang dinyatakan di atas, pusingan fungsi terbina dalam bukanlah pembundaran umum, tetapi pembundaran kepada nombor genap. Lihat di bawah untuk butiran.

fungsi terbina dalam (cth. dalam bahasa pengaturcaraan):round()

Round() disediakan sebagai fungsi terbina dalam. Ia boleh digunakan tanpa mengimport sebarang modul.

Argumen pertama ialah nombor asal, dan argumen kedua ialah bilangan digit (berapa digit untuk dibundarkan).

Bundarkan perpuluhan kepada sebarang nombor digit.

Berikut ialah contoh pemprosesan untuk jenis apungan titik terapung.

Jika hujah kedua ditinggalkan, ia dibundarkan kepada integer. Jenis juga menjadi jenis integer int.

f = 123.456

print(round(f))
# 123

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

Jika hujah kedua ditentukan, ia mengembalikan jenis apungan titik terapung.

Jika integer positif ditentukan, tempat perpuluhan ditentukan; jika integer negatif dinyatakan, tempat integer ditentukan. -1 pusingan ke persepuluh terdekat, -2 pusingan ke perseratus terdekat, dan 0 pusingan ke integer (tempat pertama), tetapi mengembalikan jenis apungan, tidak seperti apabila ditinggalkan.

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

Bundarkan integer kepada sebarang nombor digit.

Berikut ialah contoh pemprosesan untuk jenis integer int.

Jika argumen kedua ditinggalkan, atau jika 0 atau integer positif ditentukan, nilai asal dikembalikan sebagaimana adanya. Jika integer negatif ditentukan, ia dibundarkan kepada digit integer yang sepadan. Dalam kedua-dua kes, jenis integer dikembalikan.

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() membundarkan kepada nombor genap, bukan kepada pembundaran biasa

Ambil perhatian bahawa pembundaran dengan fungsi round() terbina dalam dalam Python 3 membundarkan kepada nombor genap, bukan kepada pembundaran umum.

Seperti yang ditulis dalam dokumentasi rasmi, 0.5 dibundarkan kepada 0, 5 dibundarkan kepada 0, dan seterusnya.

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

Definisi pembundaran kepada nombor genap adalah seperti berikut.

Jika pecahan kurang daripada 0.5, bulatkan ke bawah; jika pecahan lebih besar daripada 0.5, bulatkan; jika pecahan itu betul-betul 0.5, bulatkan ke atas kepada nombor genap antara membundar ke bawah dan membundarkan ke atas.
Rounding – Wikipedia

0.5 tidak selalu 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

Dalam sesetengah kes, takrif pembundaran kepada nombor genap tidak digunakan untuk pemprosesan selepas dua tempat perpuluhan.

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

Ini disebabkan oleh fakta bahawa perpuluhan tidak boleh diwakili tepat sebagai nombor titik terapung, seperti yang dinyatakan dalam dokumentasi rasmi.

Tingkah laku bulat() untuk nombor titik terapung mungkin mengejutkan anda:Sebagai contoh, pusingan(2.675, 2) akan memberi anda 2.67 dan bukannya 2.68 seperti yang dijangkakan. Ini bukan pepijat.:Ini adalah hasil daripada fakta bahawa kebanyakan perpuluhan tidak boleh diwakili dengan tepat oleh nombor titik terapung.
round() — Built-in Functions — Python 3.10.2 Documentation

Jika anda ingin mencapai pembundaran umum atau pembundaran tepat perpuluhan kepada nombor genap, anda boleh menggunakan kuantiti perpuluhan perpustakaan standard (diterangkan di bawah) atau mentakrifkan fungsi baharu.

Juga ambil perhatian bahawa round() dalam Python 2 bukanlah pembundaran kepada nombor genap, tetapi pembundaran.

quantize() perpuluhan perpustakaan standard

Modul perpuluhan perpustakaan standard boleh digunakan untuk mengendalikan nombor titik terapung perpuluhan tepat.

Menggunakan kaedah quantize() modul perpuluhan, adalah mungkin untuk membundarkan nombor dengan menentukan mod pembundaran.

Nilai yang ditetapkan untuk pembundaran hujah kaedah quantize() mempunyai makna berikut, masing-masing.

  • ROUND_HALF_UP:Pembundaran umum
  • ROUND_HALF_EVEN:Membundarkan kepada nombor genap

Modul perpuluhan ialah perpustakaan standard, jadi tiada pemasangan tambahan diperlukan, tetapi pengimportan diperlukan.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Mencipta objek Perpuluhan

Decimal() boleh digunakan untuk mencipta objek jenis Decimal.

Jika anda menentukan jenis apungan sebagai hujah, anda boleh melihat nilai yang sebenarnya dianggap sebagai.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

Seperti yang ditunjukkan dalam contoh, 0.05 tidak dianggap tepat sebagai 0.05. Inilah sebab mengapa fungsi terbina dalam round() yang diterangkan di atas dibundarkan kepada nilai yang berbeza daripada yang dijangkakan untuk nilai perpuluhan termasuk 0.05 dalam contoh.

Oleh kerana 0.5 ialah separuh (-1 kuasa 2), ia boleh dinyatakan dengan tepat dalam tatatanda binari.

print(Decimal(0.5))
# 0.5

Jika anda menentukan jenis rentetan str dan bukannya jenis apungan, ia akan dianggap sebagai jenis Perpuluhan bagi nilai yang tepat.

print(Decimal('0.05'))
# 0.05

Membundarkan perpuluhan kepada sebarang nombor digit dan membundarkan kepada nombor genap

Panggil quantize() daripada objek jenis Decimal untuk membulatkan nilai.

Argumen pertama quantize() ialah rentetan dengan bilangan digit yang sama dengan bilangan digit yang anda ingin cari, seperti ‘0.1’ atau ‘0.01’.

Di samping itu, hujah ROUNDING menentukan mod pembundaran; jika ROUND_HALF_UP ditentukan, pembundaran umum digunakan.

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

Tidak seperti fungsi terbina dalam round(), 0.5 dibundarkan kepada 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

Jika pembundaran hujah ditetapkan kepada ROUND_HALF_EVEN, pembundaran dilakukan kepada nombor genap seperti dalam pusingan fungsi terbina dalam().

Seperti yang dinyatakan di atas, jika jenis apungan titik terapung ditentukan sebagai hujah bagi Perpuluhan(), ia dianggap sebagai objek Perpuluhan dengan nilai yang sama dengan nilai sebenar jenis apungan, jadi hasil daripada penggunaan quantize() kaedah akan berbeza daripada apa yang dijangkakan, sama seperti fungsi terbina dalam 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

Jika hujah Perpuluhan() ditentukan sebagai rentetan jenis str, ia dianggap sebagai objek Perpuluhan dengan nilai itu, jadi hasilnya adalah seperti yang dijangkakan.

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

Memandangkan 0.5 boleh dikendalikan dengan betul oleh jenis apungan, tiada masalah dalam menentukan jenis apungan sebagai hujah Perpuluhan() apabila membundarkan kepada integer, tetapi adalah lebih selamat untuk menentukan jenis str rentetan apabila membundarkan ke tempat perpuluhan.

Sebagai contoh, 2.675 sebenarnya adalah 2.67499…. dalam jenis apungan. Oleh itu, jika anda ingin membundarkan kepada dua tempat perpuluhan, anda mesti menentukan rentetan kepada Perpuluhan(), jika tidak, hasilnya akan berbeza daripada hasil yang dijangkakan sama ada anda membundarkan kepada nombor bulat terdekat (ROUND_HALF_UP) atau kepada nombor 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

Ambil perhatian bahawa kaedah quantize() mengembalikan nombor jenis Decimal, jadi jika anda ingin mengendalikan nombor jenis float, anda perlu menukarnya kepada jenis float menggunakan float(), jika tidak ralat akan berlaku.

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

Membundarkan integer kepada sebarang nombor digit dan membundarkan kepada nombor genap

Jika anda ingin membundarkan kepada digit integer, menyatakan sesuatu seperti ’10’ sebagai hujah pertama tidak akan memberikan anda hasil yang diingini.

i = 99518

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

Ini kerana quantize() melakukan pembundaran mengikut eksponen objek Perpuluhan, tetapi eksponen Perpuluhan(’10’) ialah 0, bukan 1.

Anda boleh menentukan eksponen arbitrari dengan menggunakan E sebagai rentetan eksponen (cth., ‘1E1’). Eksponen eksponen boleh disemak dalam kaedah 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)

Oleh itu, hasilnya akan berada dalam notasi eksponen menggunakan E. Jika anda ingin menggunakan notasi biasa, atau jika anda ingin beroperasi dengan jenis integer int selepas pembundaran, gunakan int() untuk menukar hasilnya.

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

Jika pembundaran hujah ditetapkan kepada ROUND_HALF_UP, pembundaran umum akan berlaku, contohnya, 5 akan dibundarkan kepada 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

Sudah tentu, tidak ada masalah jika anda menentukannya sebagai rentetan.

Tentukan fungsi baharu

Kaedah menggunakan modul perpuluhan adalah tepat dan selamat, tetapi jika anda tidak selesa dengan penukaran jenis, anda boleh menentukan fungsi baharu untuk mencapai pembundaran umum.

Terdapat banyak cara yang mungkin untuk melakukan ini, sebagai contoh, fungsi berikut.

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

Jika anda tidak perlu menentukan bilangan digit dan sentiasa bulatkan ke tempat perpuluhan pertama, anda boleh menggunakan bentuk yang lebih mudah.

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

Jika anda perlu tepat, adalah lebih selamat untuk menggunakan perpuluhan.

Berikut adalah untuk rujukan sahaja.

Bundarkan perpuluhan kepada sebarang nombor digit.

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

Tidak seperti pusingan, 0.5 menjadi 1 seperti pembundaran umum.

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

Bundarkan integer kepada sebarang nombor digit

i = 99518

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

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

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

Tidak seperti pusingan, 5 menjadi 10 mengikut pembundaran biasa.

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

Nota: Untuk nilai negatif

Dalam contoh fungsi di atas, -0.5 dibundarkan kepada 0.

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

Terdapat pelbagai cara berfikir tentang pembundaran untuk nilai negatif, tetapi jika anda ingin menjadikan -0.5 menjadi -1, anda boleh mengubah suainya seperti berikut, sebagai contoh

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