فصل ۲: داده‌ها — متغیر، عدد، پول، متن فارسی و ورودی

اعداد و پول: int، float، دام 0.1+0.2 و Decimal برای ریال و تومان

ماشین‌حسابی که همیشه راست نمی‌گوید

پایتون دو نوع عددی اصلی دارد: int (عدد صحیح) و float (عدد اعشاری). int در پایتون اندازه‌ی نامحدود دارد؛ 2 ** 200 بدون سرریز محاسبه می‌شود. float اما همان استاندارد IEEE 754 است که در همه‌ی زبان‌ها وجود دارد و دقتی حدود ۱۵ تا ۱۷ رقم دارد.

عملگرها

عملگرمعنیمثالنتیجه
/تقسیم؛ همیشه float7 / 23.5
//تقسیم صحیح (رو به پایین)7 // 23
%باقی‌مانده7 % 21
**توان2 ** 101024
divmodخارج‌قسمت و باقی‌مانده با همdivmod(125, 60)(2, 5)

دقت کنید // رو به پایین گرد می‌کند، نه رو به صفر: -7 // 2 برابر ‎-4 است. divmod برای تبدیل دقیقه به ساعت و دقیقه یا سانتی‌متر به متر و سانتی‌متر بسیار کاربردی است.

دام معروف 0.1 + 0.2

>>> 0.1 + 0.2
0.30000000000000004
>>> 0.1 + 0.2 == 0.3
False
>>> import math
>>> math.isclose(0.1 + 0.2, 0.3)
True

این باگ پایتون نیست. کامپیوتر اعداد را در مبنای ۲ ذخیره می‌کند و 0.1 در مبنای ۲ یک کسر متناوب است، همان‌طور که 1/3 در مبنای ۱۰ برابر 0.333… است. نتیجه: هیچ‌وقت دو float را با == مقایسه نکنید و هیچ‌وقت پول را با float حساب نکنید.

پول: دو راه درست

راه اول، int به ریال: ریال واحد خرد ندارد، پس همه‌ی مبالغ را به‌صورت عدد صحیح ریالی نگه دارید و فقط هنگام نمایش به تومان تبدیل کنید. ساده، سریع و بدون خطای گرد کردن.

راه دوم، Decimal: وقتی درصد، نرخ ارز یا اعشار دارید، از ماژول decimal استفاده کنید که محاسبه را در مبنای ۱۰ و دقیق انجام می‌دهد:

from decimal import Decimal, ROUND_HALF_UP

price_rial = Decimal("12500000")        # قیمت یک تخته فرش
vat = Decimal("0.10")                    # مالیات بر ارزش افزوده
total = price_rial * (1 + vat)
print(total)                             # 13750000.00

rate = Decimal("2.675")
print(rate.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))  # 2.68

toman = int(total) // 10
print(f"{toman:,} تومان")                # 1,375,000 تومان

Decimal را همیشه از رشته بسازید. Decimal(0.1) همان خطای float را با خودش می‌آورد و عددی با ۵۵ رقم اعشار تحویل می‌دهد.

گرد کردن بانکی

تابع round در پایتون از «گرد کردن بانکی» استفاده می‌کند: عدد دقیقاً وسط را به نزدیک‌ترین عدد زوج گرد می‌کند. پس round(2.5) برابر 2 و round(3.5) برابر 4 است. برای فاکتور که انتظار «نیم به بالا» دارد، از quantize با ROUND_HALF_UP استفاده کنید.

نکته‌هایی که کمتر کسی می‌داند

  • round(2.675, 2) برابر 2.67 است نه 2.68؛ چون 2.675 در حافظه در واقع کمی کمتر از 2.675 ذخیره شده است. این یکی گرد کردن بانکی نیست، خطای float است.
  • float("nan") == float("nan") برابر False است؛ NaN تنها مقداری است که با خودش برابر نیست. برای بررسی از math.isnan استفاده کنید.
  • زیرخط در اعداد (12_500_000) فقط برای چشم است؛ int("12_500") هم کار می‌کند، ولی int("12,500") خطا می‌دهد.
  • 10 / 2 برابر 5.0 است نه 5؛ اگر نتیجه را برای اندیس لیست یا range لازم دارید، از // استفاده کنید.
  • عدد صحیحی با بیش از ۴۳۰۰ رقم را پایتون به‌طور پیش‌فرض به رشته تبدیل نمی‌کند (محافظت در برابر حمله‌ی DoS)؛ اگر واقعاً لازم شد، sys.set_int_max_str_digits را تغییر دهید.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.