Python тілінде «дөңгелек» және «Decimal.quantize» көмегімен ондық және бүтін сандарды дөңгелектеу

Іскерлік

Төменде Python жүйесінде сандарды жұп санға дейін дөңгелектеу немесе дөңгелектеу әдісі түсіндіріледі. Сандар өзгермелі нүктелі float немесе бүтін int типті болып есептеледі.

  • кірістірілген функция (мысалы, бағдарламалау тілінде):round()
    • Ондық бөлшектерді цифрлардың кез келген санына дейін дөңгелектеу.
    • Бүтін сандарды цифрлардың кез келген санына дейін дөңгелектеу.
    • round() жалпы дөңгелектеуге емес, жұп санға айналдырады
  • стандартты кітапханаdecimalquantize()
    • DecimalОбъектіні құру
    • Ондық бөлшектерді кез келген цифрлар санына дейін дөңгелектеу және жұп сандарға дейін дөңгелектеу
    • Бүтін сандарды цифрлардың кез келген санына дейін дөңгелектеу және жұп сандарға дейін дөңгелектеу
  • Жаңа функцияны анықтаңыз
    • Ондық бөлшектерді цифрлардың кез келген санына дейін дөңгелектеңіз.
    • Бүтін сандарды цифрлардың кез келген санына дейін дөңгелектеу
    • Ескертпе: теріс мәндер үшін

Назар аударыңыз, жоғарыда айтылғандай, кірістірілген функция айналымы жалпы дөңгелектеу емес, жұп санға дейін дөңгелектеу болып табылады. Мәліметтерді төменде қараңыз.

кірістірілген функция (мысалы, бағдарламалау тілінде):round()

Round() кірістірілген функция ретінде қамтамасыз етілген. Оны ешқандай модульдерді импорттаусыз пайдалануға болады.

Бірінші аргумент – бастапқы сан, ал екінші аргумент – цифрлар саны (қанша цифрға дейін дөңгелектеу керек).

Ондық бөлшектерді цифрлардың кез келген санына дейін дөңгелектеу.

Төменде қалқымалы нүкте қалқымалы түрі үшін өңдеудің мысалы келтірілген.

Екінші аргумент түсірілсе, ол бүтін санға дейін дөңгелектенеді. Түр де бүтін int түріне айналады.

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

Бүтін сандарды цифрлардың кез келген санына дейін дөңгелектеу.

Төменде бүтін int түрі үшін өңдеудің мысалы келтірілген.

Екінші аргумент түсірілсе немесе 0 немесе оң бүтін сан көрсетілсе, бастапқы мән сол күйінде қайтарылады. Теріс бүтін сан көрсетілсе, ол сәйкес бүтін санға дейін дөңгелектенеді. Екі жағдайда да бүтін 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() жалпы дөңгелектеуге емес, жұп санға айналдырады

Python 3 жүйесіндегі кіріктірілген round() функциясымен дөңгелектеу жалпы дөңгелектеу үшін емес, жұп санға айналатынын ескеріңіз.

Ресми құжаттамада жазылғандай, 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

Бұл ресми құжаттамада айтылғандай ондық бөлшектерді жылжымалы нүкте сандары ретінде көрсету мүмкін еместігіне байланысты.

Жылжымалы нүкте сандары үшін round() әрекеті сізді таң қалдыруы мүмкін:Мысалы, round(2,675, 2) сізге күтілгендей 2,68 орнына 2,67 береді. Бұл қате емес.:Бұл ондық бөлшектердің көпшілігін жылжымалы нүкте сандарымен дәл көрсету мүмкін еместігінің нәтижесі.
round() — Built-in Functions — Python 3.10.2 Documentation

Егер жалпы дөңгелектеу немесе ондық бөлшектерді жұп сандарға дәл дөңгелектеу қол жеткізгіңіз келсе, стандартты кітапханалық ондық кванттауды (төменде сипатталған) пайдалануға немесе жаңа функцияны анықтауға болады.

Сондай-ақ, Python 2-де round() жұп санға дейін дөңгелектеу емес, дөңгелектеу екенін ескеріңіз.

стандартты кітапханалық ондық санның quantize().

Стандартты кітапхананың ондық модулін дәл ондық өзгермелі нүкте сандарын өңдеу үшін пайдалануға болады.

Ондық модульдің quantize() әдісін пайдаланып, дөңгелектеу режимін көрсету арқылы сандарды дөңгелектеуге болады.

quantize() әдісінің аргументтерін дөңгелектеу үшін орнатылған мәндер сәйкесінше келесі мағыналарға ие.

  • ROUND_HALF_UP:Жалпы дөңгелектеу
  • ROUND_HALF_EVEN:Жұп сандарға дейін дөңгелектеу

Ондық модуль стандартты кітапхана болып табылады, сондықтан қосымша орнату қажет емес, бірақ импорттау қажет.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Ондық объектіні құру

Decimal() Decimal түріндегі нысандарды жасау үшін пайдаланылуы мүмкін.

Аргумент ретінде қалқымалы түрді көрсетсеңіз, мәннің шын мәнінде не ретінде қарастырылатынын көре аласыз.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

Мысалда көрсетілгендей, 0,05 дәл 0,05 ретінде қарастырылмайды. Жоғарыда сипатталған кірістірілген round() функциясының мысалдағы 0,05-ті қоса алғанда, ондық мәндер үшін күтілгеннен басқа мәнге дөңгелектенуінің себебі осы.

0,5 бір жарым (2-нің -1 дәрежесі) болғандықтан, оны екілік жүйеде дәл көрсетуге болады.

print(Decimal(0.5))
# 0.5

Қалқымалы түрдің орнына str жол түрін көрсетсеңіз, ол нақты мәннің Ондық түрі ретінде қарастырылады.

print(Decimal('0.05'))
# 0.05

Ондық бөлшектерді кез келген цифрлар санына дейін дөңгелектеу және жұп сандарға дейін дөңгелектеу

Мәнді дөңгелектеу үшін Decimal түріндегі нысаннан quantize() шақырыңыз.

quantize() функциясының бірінші аргументі – сіз тапқыңыз келетін цифрлар санымен бірдей сандар саны бар жол, мысалы, «0,1» немесе «0,01».

Сонымен қатар, ROUNDING аргументі дөңгелектеу режимін көрсетеді; егер ROUND_HALF_UP көрсетілсе, жалпы дөңгелектеу қолданылады.

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

Кірістірілген round() функциясынан айырмашылығы 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

Аргументті дөңгелектеу ROUND_HALF_EVEN мәніне орнатылса, дөңгелектеу ендірілген функциядағы round() сияқты жұп сандарға орындалады.

Жоғарыда айтылғандай, өзгермелі нүктелі қалқыма түрі Decimal() аргументі ретінде көрсетілсе, ол өзгермелі түрдің нақты мәніне тең мәні бар Ондық нысан ретінде қарастырылады, сондықтан quantize() функциясын пайдалану нәтижесі. әдіс кірістірілген 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

Decimal() аргументі str түріндегі жол ретінде көрсетілсе, ол дәл осы мәннің Ондық нысаны ретінде қарастырылады, сондықтан нәтиже күтілгендей болады.

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 мәні қалқымалы түрмен дұрыс өңделуі мүмкін болғандықтан, бүтін санға дейін дөңгелектеу кезінде Decimal() аргументі ретінде қалқымалы түрді көрсетуде ешқандай проблема жоқ, бірақ ондық бөлшекке дейін дөңгелектеу кезінде str жолының түрін көрсету қауіпсізрек.

Мысалы, қалқымалы түрдегі 2,675 шын мәнінде 2,67499…. болып табылады. Сондықтан, екі ондық таңбаға дейін дөңгелектегіңіз келсе, Decimal() мәніне жолды көрсетуіңіз керек, әйтпесе нәтиже ең жақын бүтін санға (ROUND_HALF_UP) немесе жұп санға (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

quantize() әдісі Ондық түрдегі нөмірді қайтаратынын ескеріңіз, сондықтан өзгермелі түрдегі санмен жұмыс жасағыңыз келсе, оны float() көмегімен қалқымалы түрге түрлендіру керек, әйтпесе қате орын алады.

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

Себебі quantize() Decimal нысанының көрсеткішіне сәйкес дөңгелектеуді орындайды, бірақ Decimal(’10’) көрсеткіші 1 емес, 0.

Көрсеткіштік жол ретінде E пайдалану арқылы ерікті көрсеткішті көрсетуге болады (мысалы, ‘1E1’). Көрсеткіш көрсеткішін 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)

Нәтиже E көмегімен экспоненциалды белгілеуде болады. Егер қалыпты белгілерді пайдаланғыңыз келсе немесе дөңгелектенгеннен кейін бүтін int түрімен жұмыс істегіңіз келсе, нәтижені түрлендіру үшін int() пайдаланыңыз.

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

Аргументті дөңгелектеу ROUND_HALF_UP мәніне орнатылса, жалпы дөңгелектеу орын алады, мысалы, 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