Заокруживање децимала и целих бројева у Питхон-у са „роунд“ и „Децимал.куантизе“

Бусинесс

У наставку је објашњено како заокружити бројеве у Питхон-у заокружујући или заокружујући на паран број. Претпоставља се да су бројеви типа флоат са помичним зарезом или интегер инт.

  • уграђена функција (нпр. у програмском језику):round()
    • Заокружите децимале на било који број цифара.
    • Заокружите целе бројеве на било који број цифара.
    • роунд() заокружује на паран број, а не на уобичајено заокруживање
  • стандардна библиотекаdecimalquantize()
    • DecimalКреирање објекта
    • Заокруживање децимала на било који број цифара и заокруживање на парне бројеве
    • Заокруживање целих бројева на било који број цифара и заокруживање на парне бројеве
  • Дефинишите нову функцију
    • Заокружите децимале на било који број цифара.
    • Заокружите целе бројеве на било који број цифара
    • Напомена: За негативне вредности

Имајте на уму да, као што је горе поменуто, заокруживање уграђене функције није опште заокруживање, већ заокруживање на паран број. Погледајте испод за детаље.

уграђена функција (нпр. у програмском језику):round()

Роунд() је обезбеђен као уграђена функција. Може се користити без увоза модула.

Први аргумент је оригинални број, а други аргумент је број цифара (на колико цифара треба заокружити).

Заокружите децимале на било који број цифара.

Следи пример обраде за тип са плутајућим зарезом.

Ако је други аргумент изостављен, заокружује се на цео број. Тип такође постаје целобројни инт тип.

f = 123.456

print(round(f))
# 123

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

Ако је наведен други аргумент, он враћа тип са помичним зарезом.

Ако је наведен позитиван цео број, наводи се децимално место; ако је наведен негативан цео број, наведено је целобројно место. -1 се заокружује на најближу десетину, -2 заокружује на најближу стоту и 0 заокружује на цео број (прво место), али враћа тип са плутајућим бројем, за разлику од када се изостави.

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

Заокружите целе бројеве на било који број цифара.

Следи пример обраде целобројног типа инт.

Ако је други аргумент изостављен, или ако је наведен 0 или позитиван цео број, оригинална вредност се враћа онаква каква јесте. Ако је наведен негативан цео број, он се заокружује на одговарајућу цифру целог броја. У оба случаја, враћа се целобројни инт тип.

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

роунд() заокружује на паран број, а не на уобичајено заокруживање

Имајте на уму да се заокруживање са уграђеном функцијом роунд() у Питхон 3 заокружује на паран број, а не на опште заокруживање.

Као што је написано у званичној документацији, 0,5 се заокружује на 0, 5 се заокружује на 0, и тако даље.

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

Дефиниција заокруживања на паран број је следећа.

Ако је разломак мањи од 0,5, заокружите га надоле; ако је разломак већи од 0,5, заокружити га; ако је разломак тачно 0,5, заокружите га на паран број између заокруживања наниже и заокруживања нагоре.
Rounding – Wikipedia

0,5 није увек скраћено.

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

У неким случајевима, дефиниција заокруживања на паран број не важи ни за обраду после две децимале.

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

То је због чињенице да се децимале не могу тачно представити као бројеви са покретним зарезом, као што је наведено у званичној документацији.

Понашање роунд() за бројеве са покретним зарезом може да вас изненади:На пример, круг (2,675, 2) ће вам дати 2,67 уместо 2,68 као што се очекивало. Ово није грешка.:Ово је резултат чињенице да већина децимала не може бити тачно представљена бројевима са покретним зарезом.
round() — Built-in Functions — Python 3.10.2 Documentation

Ако желите да постигнете опште заокруживање или тачно заокруживање децимала на парне бројеве, можете користити стандардну библиотеку децималног квантовања (описано у наставку) или дефинисати нову функцију.

Такође имајте на уму да роунд() у Питхон-у 2 није заокруживање на паран број, већ заокруживање.

куантизе() децимале стандардне библиотеке

Децимални модул стандардне библиотеке може се користити за руковање тачним децималним бројевима са покретним зарезом.

Користећи методу куантизе() децималног модула, могуће је заокружити бројеве навођењем начина заокруживања.

Постављене вредности за заокруживање аргумената методе куантизе() имају следећа значења, респективно.

  • ROUND_HALF_UP:Опште заокруживање
  • ROUND_HALF_EVEN:Заокруживање на парне бројеве

Децимални модул је стандардна библиотека, тако да није потребна додатна инсталација, али је неопходан увоз.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Креирање децималног објекта

Децимал() се може користити за креирање објеката типа Децимал.

Ако наведете тип флоат као аргумент, можете видети како се вредност заправо третира.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

Као што је приказано у примеру, 0,05 се не третира као тачно 0,05. Ово је разлог зашто је уграђена функција роунд() описана изнад заокружила на другачију вредност од очекиване за децималне вредности укључујући 0,05 у примеру.

Пошто је 0,5 једна половина (-1 степен од 2), може се тачно изразити у бинарној нотацији.

print(Decimal(0.5))
# 0.5

Ако наведете тип стринга стр уместо типа флоат, он ће се третирати као децимални тип тачне вредности.

print(Decimal('0.05'))
# 0.05

Заокруживање децимала на било који број цифара и заокруживање на парне бројеве

Позовите куантизе() из објекта типа Децимал да бисте заокружили вредност.

Први аргумент куантизе() је стринг са истим бројем цифара као и број цифара које желите да пронађете, као што је ‘0.1’ или ‘0.01’.

Поред тога, аргумент РОУНДИНГ специфицира начин заокруживања; ако је назначено РОУНД_ХАЛФ_УП, користи се опште заокруживање.

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

За разлику од уграђене функције роунд(), 0,5 се заокружује на 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

Ако је заокруживање аргумента постављено на РОУНД_ХАЛФ_ЕВЕН, заокруживање се врши на парне бројеве као у уграђеној функцији роунд().

Као што је горе поменуто, ако је тип флоат са помичним зарезом наведен као аргумент Децимал(), он се третира као Децимал објекат са вредношћу једнаком стварној вредности типа флоат, тако да је резултат коришћења куантизе() метод ће се разликовати од онога што се очекује, баш као и уграђена функција роунд().

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

Ако је аргумент Децимал() наведен као стринг типа стр, он се третира као Децимални објекат тачно те вредности, тако да је резултат очекиван.

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

Пошто тип флоат може исправно да обради 0,5, нема проблема у навођењу типа флоат као аргумента Децимал() када се заокружује на цео број, али је сигурније навести стринг тип стр када се заокружује на децимално место.

На пример, 2,675 је у ствари 2,67499…. у плутајућем облику. Стога, ако желите да заокружите на две децимале, морате да наведете стринг на Децимал(), иначе ће резултат бити другачији од очекиваног резултата било да заокружујете на најближи цео број (РОУНД_ХАЛФ_УП) или на паран број (РОУНД_ХАЛФ_ЕВЕН ).

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

Имајте на уму да метода куантизе() враћа број типа децималног типа, тако да ако желите да оперишете са бројем типа флоат, потребно је да га конвертујете у флоат тип помоћу флоат(), иначе ће доћи до грешке.

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

Заокруживање целих бројева на било који број цифара и заокруживање на парне бројеве

Ако желите да заокружите на цео број, навођење нечег попут ’10’ као првог аргумента неће вам дати жељени резултат.

i = 99518

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

То је зато што куантизе() обавља заокруживање према експоненту Децимал објекта, али експонент Децимал(’10’) је 0, а не 1.

Можете да наведете произвољан експонент користећи Е као стринг експонента (нпр. ‘1Е1’). Експонент експонента се може проверити у методи ас_тупле.

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)

Како јесте, резултат ће бити у експоненцијалној нотацији користећи Е. Ако желите да користите нормалну нотацију, или ако желите да радите са целим бројем типа инт након заокруживања, користите инт() да конвертујете резултат.

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

Ако је заокруживање аргумента постављено на РОУНД_ХАЛФ_УП, доћи ће до општег заокруживања, нпр. 5 ће бити заокружено на 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

Наравно, нема проблема ако га наведете као стринг.

Дефинишите нову функцију

Метод коришћења децималног модула је прецизан и сигуран, али ако вам није пријатна конверзија типа, можете дефинисати нову функцију да бисте постигли опште заокруживање.

Постоји много могућих начина да се то уради, на пример, следећа функција.

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

Ако не морате да наведете број цифара и увек заокружите на прву децималу, можете користити једноставнији образац.

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

Ако треба да будете прецизни, сигурније је користити децимални.

Следеће је само за референцу.

Заокружите децимале на било који број цифара.

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

За разлику од рунде, 0,5 постаје 1 према општем заокруживању.

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

Заокружите целе бројеве на било који број цифара

i = 99518

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

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

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

За разлику од круга, 5 постаје 10 према уобичајеном заокруживању.

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

Напомена: За негативне вредности

У примеру функције изнад, -0,5 је заокружено на 0.

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

Постоје различити начини размишљања о заокруживању негативних вредности, али ако желите да претворите -0,5 у -1, можете то изменити на следећи начин, нпр.

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