Asosiy kontentga o‘tish
Innovialabs

Nega 0.1 + 0.2 ≠ 0.3: suzuvchi nuqtali sonlar va pul kodda

Amaliyot3 daq

Qisqacha

Float sonlarni ikkilik tizimda taxminan saqlaydi, shuning uchun pul eng kichik birlikdagi butun son (tiyin, sent) yoki Decimal va NUMERIC kabi o‘nlik turlarda saqlanadi.

Qisqa javob

Ko‘pchilik dasturlash tillari kasr sonlarni IEEE 754 standarti bo‘yicha — ikkilik tizimda saqlaydi. Ikkilik tizimda 0.1 cheksiz kasr, xuddi o‘nlik tizimdagi 1/3 kabi. Kompyuter uni kesib tashlaydi va xotirada juda yaqin, lekin aniq bo‘lmagan qiymat qoladi.

0.1 + 0.2            // 0.30000000000000004
0.1 + 0.2 === 0.3    // false

Ilmiy hisob-kitoblar uchun bunday xatolik odatda ahamiyatsiz. Pul uchun esa muhim: bitta operatsiyada yo‘qolgan tiyin hisobotdagi tafovutga aylanadi, to‘lov summasi esa chekdagi summaga mos kelmay qoladi.

Qoida: pulni float va double da saqlamang va hisoblamang.

Float qanday tuzilgan

IEEE 754 formatidagi son uch qismdan iborat: ishora, mantissa (ahamiyatli raqamlar) va eksponenta (nuqtani qayerga surish). double turi taxminan 15–17 ta ahamiyatli o‘nlik raqam beradi.

Bundan ikki xil muammo kelib chiqadi:

  • Ifodalab bo‘lmaydigan kasrlar. 0.1, 0.2, 0.7 ni ikkilik tizimda aniq yozib bo‘lmaydi.
  • Katta sonlarda aniqlik yo‘qolishi. Son juda katta bo‘lsa, kichik razryadlar mantissaga sig‘maydi.

Xatolar yig‘iladi: 0.1 ni ming marta qo‘shing — natija 100 dan sezilarli farq qiladi.

1-usul: eng kichik birlikdagi butun sonlar

Summani valyutaning eng kichik birligida butun son sifatida saqlang: dollar uchun sent, so‘m uchun tiyin.

  • 15 000,50 so‘m → 1500050 tiyin
  • $19.99 → 1999 sent

Butun sonlar aniq qo‘shiladi va ayiriladi. Odam o‘qiydigan ko‘rinishga faqat ekranga chiqarishda o‘tkaziladi.

price_tiyin = 1_500_050
qty = 3
total_tiyin = price_tiyin * qty           # 4 500 150, aniq
print(f"{total_tiyin / 100:,.2f} so‘m")   # faqat ko‘rsatish uchun

Yodda tuting: valyutalarda verguldan keyingi xonalar soni har xil. ISO 4217 bo‘yicha o‘zbek so‘mida ular ikkita, garchi tiyinlar naqd muomalada deyarli uchramasa ham. Ko‘p tizimlar so‘mni to‘g‘ridan-to‘g‘ri butun so‘mlarda hisoblaydi — bu talablarda qayd etilgan bo‘lsa, maqbul.

2-usul: o‘nlik (decimal) turlar

O‘nlik turlar sonni o‘nlik tizimda saqlaydi va ikkilik xatolarsiz hisoblaydi.

MuhitTur
Pythondecimal.Decimal
JavaBigDecimal
C#decimal
PostgreSQL, MySQLNUMERIC(p, s) / DECIMAL(p, s)
JavaScripto‘nlik arifmetika uchun tashqi kutubxonalar
from decimal import Decimal, ROUND_HALF_UP

a = Decimal("0.1") + Decimal("0.2")   # natija: aniq 0.3
vat = (Decimal("15000.50") * Decimal("0.12")).quantize(
    Decimal("0.01"), rounding=ROUND_HALF_UP
)

Decimal ni float dan emas, satrdan yarating: Decimal(0.1) o‘sha xatolikni meros qilib oladi.

Yaxlitlash — biznes qoidasi

Aniq turlar bilan ham pulni yaxlitlashga to‘g‘ri keladi: soliqlar, chegirmalar, valyuta kurslari. Oldindan belgilab oling:

  • Yaxlitlash rejimi. Matematik «yarmi yuqoriga» yoki bank usuli (juftga qarab). Masalan, Python dagi o‘rnatilgan round() bank usulidan foydalanadi.
  • Yaxlitlash payti. Chekning har bir qatorida yoki faqat yakuniy summada — natijalar farq qilishi mumkin.
  • Summani bo‘lish. 100 uchga teng bo‘linmaydi: 33.33 + 33.33 + 33.34. Qoldiq aniq tarzda qismlardan biriga beriladi.

Loyiha uchun chek-list

  1. Ma’lumotlar bazasida — NUMERIC yoki eng kichik birlikdagi butun son, hech qachon FLOAT yoki REAL emas.
  2. API da — summalar satr ("15000.50") yoki eng kichik birlikdagi butun son ko‘rinishida, yonida valyuta kodi bilan.
  3. Valyuta summa bilan birga saqlanadi, taxmin qilinmaydi.
  4. Yaxlitlash qoidalari talablarda yozilgan va testlar bilan qoplangan.
  5. Valyuta kurslari yetarli aniqlik va sana bilan saqlanadi.
  6. Frontend summalarni faqat ko‘rsatadi, yakuniy hisobni server qiladi.

Ko‘p uchraydigan xatolar

  • Float larni == orqali solishtirish.
  • Formadan kelgan summalarga parseFloat qo‘llab, keyin arifmetika qilish.
  • Aniqlik bo‘yicha kelishuvsiz JSON da money turi yoki float.
  • Qoidasiz har bir oraliq bosqichda yaxlitlash.

Ko‘p beriladigan savollar

Ko‘rsatish uchun — ha, hisoblash uchun — xavfli. Xatolar operatsiyalar zanjirida yig‘iladi va oxirida yaxlitlash har doim ham to‘g‘ri natijani qaytarmaydi.

Bunda yordam beramiz

O‘zingiz shug‘ullanmasdan natija olishni istasangiz — biz har kuni shu bilan shug‘ullanamiz.

Loyihani muhokama qilish

Yana o‘qing

G‘oya yoki vazifangiz bormi? Bizga aytib bering

Ish kuni davomida javob beramiz va yechim taklif qilamiz. Konsultatsiya bepul.