گرد کردن اعشار و اعداد صحیح در پایتون با “round” و “Decimal.quantize”

کسب و کار

در ادامه نحوه گرد کردن اعداد در پایتون با گرد کردن یا گرد کردن به یک عدد زوج توضیح داده شده است. فرض می شود اعداد از نوع شناور ممیز شناور یا عدد صحیح 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() به یک عدد زوج تبدیل می شود، نه به یک گرد کردن معمولی

توجه داشته باشید که گرد کردن با تابع ()round داخلی در پایتون 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

این به دلیل این واقعیت است که اعشار را نمی توان دقیقاً به عنوان اعداد ممیز شناور، همانطور که در اسناد رسمی ذکر شده است، نشان داد.

رفتار round() برای اعداد ممیز شناور ممکن است شما را شگفت زده کند:به عنوان مثال، دور (2.675، 2) به جای 2.68 همانطور که انتظار می رود، 2.67 به شما می دهد. این یک خطا نیست.:این نتیجه این واقعیت است که اکثر اعشار را نمی توان دقیقاً با اعداد ممیز شناور نشان داد.
round() — Built-in Functions — Python 3.10.2 Documentation

اگر می‌خواهید به گرد کردن کلی یا گرد کردن دقیق اعشار به اعداد زوج برسید، می‌توانید از کوانتیز اعشاری استاندارد کتابخانه (که در زیر توضیح داده شده است) استفاده کنید یا یک تابع جدید تعریف کنید.

همچنین توجه داشته باشید که round() در پایتون 2 به عدد زوج گرد نمی شود، بلکه گرد کردن است.

quantize() از اعشار استاندارد کتابخانه

ماژول اعشاری کتابخانه استاندارد می تواند برای رسیدگی به اعداد ممیز شناور اعشاری دقیق استفاده شود.

با استفاده از روش quantize() ماژول اعشاری، می توان اعداد را با مشخص کردن حالت گرد کردن گرد کرد.

مقادیر مجموعه برای گرد کردن آرگومان متد quantize() به ترتیب معانی زیر را دارند.

  • ROUND_HALF_UP:گرد کردن عمومی
  • ROUND_HALF_EVEN:گرد کردن به اعداد زوج

ماژول اعشاری یک کتابخانه استاندارد است، بنابراین نیازی به نصب اضافی نیست، اما وارد کردن ضروری است.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

ایجاد یک شی اعشاری

Decimal() می تواند برای ایجاد اشیاء از نوع Decimal استفاده شود.

اگر یک نوع float را به عنوان آرگومان مشخص کنید، می توانید ببینید که مقدار در واقع به چه صورت است.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

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

همانطور که در مثال نشان داده شده است، 0.05 دقیقاً به عنوان 0.05 در نظر گرفته نمی شود. به همین دلیل است که تابع داخلی round() شرح داده شده در بالا به مقداری متفاوت از مقدار مورد انتظار برای مقادیر اعشاری از جمله 0.05 در مثال گرد شده است.

از آنجایی که 0.5 نصف است (-1 توان 2)، می توان آن را دقیقاً با نماد دودویی بیان کرد.

print(Decimal(0.5))
# 0.5

اگر به جای نوع float نوع رشته str را مشخص کنید، به عنوان نوع اعشاری مقدار دقیق در نظر گرفته می شود.

print(Decimal('0.05'))
# 0.05

گرد کردن اعشار به هر تعداد رقم و گرد کردن به اعداد زوج

برای گرد کردن مقدار () quantize را از یک شی از نوع Decimal فراخوانی کنید.

اولین آرگومان 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 () انجام می شود.

همانطور که در بالا ذکر شد، اگر یک نوع float ممیز شناور به عنوان آرگومان Decimal() مشخص شود، به عنوان یک شی اعشاری با مقداری برابر با مقدار واقعی نوع float در نظر گرفته می شود، بنابراین نتیجه استفاده از 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 می تواند به درستی توسط نوع float مدیریت شود، هیچ مشکلی در تعیین نوع float به عنوان آرگومان Decimal() هنگام گرد کردن به یک عدد صحیح وجود ندارد، اما مشخص کردن نوع رشته در هنگام گرد کردن به رقم اعشار ایمن تر است.

مثلا 2.675 در واقع 2.67499 …. در نوع float است. بنابراین، اگر می‌خواهید به دو رقم اعشار گرد کنید، باید رشته‌ای را به 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 کار کنید، باید آن را با استفاده از float () به نوع 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’) 0 است، نه 1.

می‌توانید با استفاده از 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
Copied title and URL