IlmHamroh
JavaScript Full-stack/8-qism. JavaScript asoslari30/61-dars17 daqiqa
Mundarija (33)

JavaScript'da pul hisoblash: tiyinda saqlash, yaxlitlash, chegirma va QQS

Qisqacha: Pulni JavaScript'da kasr son bilan hisoblamang: 72500 * 1.12 — 81200.00000000001. Pulni eng kichik birlikda — tiyinda — butun son sifatida saqlang: 12 500,50 so'm = 1250050 tiyin. Foiz va bo'lishdan keyin tiyinni aniq qoida bilan yaxlitlang, faqat ekranga chiqarishda so'mga aylantiring. Murakkab moliyaviy hisob uchun decimal.js kabi kutubxonalar bor.

Bu darsda

  • Nega pul uchun oddiy kasr son xavfli ekanini aniq misollarda ko'rsata olasiz.
  • Pulni tiyinda saqlab, so'mdan tiyinga va qaytarib to'g'ri aylantira olasiz.
  • Yaxlitlash qoidalarini (yuqoriga, noldan uzoqqa, "bank" usuli) farqlay olasiz.
  • Chegirma, QQS 12% va hisobni bo'lishni bir tiyin ham yo'qotmasdan hisoblay olasiz.
  • Intl.NumberFormat bilan so'mni ko'rsata olasiz va uning haqiqiy natijasidagi tuzoqlarni bilasiz.

Oldin bilishingiz kerak: Number turi JS'da, Matn ↔ son va sonni tekshirish, Math obyekti.

1. Nega bu kerak?

Oldingi darsda omonat foizini hisoblaganimizda 17279999.999999996 chiqdi. Bu tasodif emas. Keling, oddiy do'kon hisob-kitobini ko'ramiz.

Mahsulot narxi 72 500 so'm, unga 12% QQS qo'shiladi:

js
const narx = 72500;
const jami = narx * 1.12;

console.log(jami); // 81200.00000000001
console.log(jami === 81200); // false

Kassada 81 200 so'm yozilgan. Dastur esa "bu 81 200 emas" deydi. Endi hamyon balansini ko'ramiz. Mijoz uch marta 0,1 so'mlik keshbek oldi:

js
let balans = 0;
balans += 0.1;
balans += 0.1;
balans += 0.1;

console.log(balans); // 0.30000000000000004
console.log(balans === 0.3); // false

Bir marta bu arzimas xato. Lekin to'lov tizimi kuniga millionlab amal bajaradi. Kun oxirida bank hisoboti bilan dastur hisoboti bir tiyinga ham farq qilsa, hisob mos kelmaydi. Buxgalter bu farqni qo'lda qidiradi, soliq tekshiruvi savol beradi.

Hayotdan o'xshatish: bozorda bir kilo guruchni "taxminan" tortish mumkin. Bankda esa pulni "taxminan" sanab bo'lmaydi. Pul — dasturlashdagi aniqlik talab qilinadigan eng muhim joylardan biri.

2. Muammoning ildizi

Number turi darsida sababini ko'rgandik. JavaScript sonlarni ikkilik tizimda saqlaydi. 0.1 va 1.12 kabi o'nlik kasrlarni ikkilik tizimda aniq yozib bo'lmaydi — xuddi 1/3 ni o'nlik tizimda 0.3333... deb oxirigacha yoza olmaganimiz kabi.

Muhim kuzatuv: butun sonlar bilan bunday muammo yo'q.

js
console.log(45500 * 0.07); // 3185.0000000000005
console.log((45500 * 7) / 100); // 3185

Birinchi qatorda kasr 0.07 bor — xato chiqdi. Ikkinchi qatorda faqat butun sonlar: 45500 * 7 — aniq, bo'lish esa bir marta, eng oxirida. Natija aniq. Butun yechim shu g'oyaga qurilgan.

3. Yechim: pulni tiyinda saqlash

3.1 Eng kichik birlik

1 so'm = 100 tiyin. Tiyin tangalari kundalik hayotda deyarli uchramaydi, lekin banklar va to'lov tizimlari hisobni aynan tiyinda yuritadi. Masalan, Payme API va Telegram botlardagi to'lovlarda summa tiyinda yuboriladi: 50 000 so'm → 5000000.

Qoida: pulni eng kichik birlikda, butun son sifatida saqlang. Inglizcha bu minor units ("kichik birliklar") deyiladi. Dollar uchun — sent, yevro uchun — yevrosent, so'm uchun — tiyin.

js
const narxTiyin = 1_250_050; // 12 500,50 so'm

console.log(Number.isSafeInteger(narxTiyin)); // true

Butun sonlar Number.MAX_SAFE_INTEGER gacha aniq. Tiyinda bu taxminan 90 trillion so'm — oddiy do'kon yoki ilova uchun yetarli. Undan katta summalar uchun BigInt bor, uni keyingi darsda o'rganamiz.

Maslahat: Ba'zi valyutalarda kichik birlik boshqacha. Yapon iyenasida kasr yo'q (0 xona), Quvayt dinorida esa 3 xona (1 dinor = 1 000 fils). Xalqaro ilova yozsangiz, har valyutaning xonalar sonini ISO 4217 standartidan oling.

3.2 So'mdan tiyinga: faqat Math.round

Foydalanuvchi 1.15 so'm kiritdi (masalan, valyuta kursi kasr bo'lganda). Uni tiyinga aylantiramiz:

js
const som = 1.15;

console.log(som * 100); // 114.99999999999999
console.log(Math.floor(som * 100)); // 114
console.log(Math.round(som * 100)); // 115

1.15 * 100 aniq 115 emas. Math.floor yoki Math.trunc bilan bir tiyin yo'qoladi. Qoida: so'mdan tiyinga faqat Math.round(som * 100) bilan o'ting.

3.3 Satrdan tiyinga — kasr sonsiz

Undan ham ishonchlisi — kasr songa umuman tegmaslik. Foydalanuvchi "12 500,50" yozdi. Satrni vergul bo'yicha bo'lib, so'm va tiyinni alohida o'qiymiz:

js
const kiritilgan = "12 500,50";

const qismlar = kiritilgan.replaceAll(" ", "").split(",");
const som = Number(qismlar[0]);
const tiyin = Number((qismlar[1] ?? "").padEnd(2, "0"));

console.log(som * 100 + tiyin); // 1250050
  • split(",") — Kesish, bo'lish va to'ldirish darsidan: ["12500", "50"].
  • qismlar[0] va qismlar[1] — massivning birinchi va ikkinchi bo'lagi. Ular satrdagi belgilar kabi indeks bilan olinadi, sanash 0 dan boshlanadi (massiv darsida batafsil).
  • qismlar[1] ?? "" — vergul bo'lmasa, ikkinchi qism yo'q (undefined). ?? operatori uni bo'sh satr qiladi.
  • padEnd(2, "0") — "5" ni "50" ga to'ldiradi: 12 500,5 — bu 50 tiyin, 5 emas. Bo'sh satr esa "00" bo'ladi.

Bu yerda hech qanday kasr son yo'q — faqat butun sonlarni ko'paytirish va qo'shish. Real loyihada natijani oldingi darsdagidek tekshirishni ham unutmang: Number.isSafeInteger va > 0.

3.4 Tiyindan ko'rsatishga

Hisob-kitob tugadi, endi mijozga ko'rsatamiz. Faqat shu yerda bo'lamiz:

js
const jamiTiyin = 1250050;

console.log((jamiTiyin / 100).toFixed(2)); // 12500.50

Butun sonni 100 ga bo'lish va darhol toFixed(2) qilish ko'rsatish uchun xavfsiz. Natija — satr, u bilan boshqa hisob qilinmaydi. Chiroyliroq ko'rinishni 8-bo'limda ko'ramiz.

Tekshirib ko'ring: Foydalanuvchi "350,7" yozdi. 3.3 dagi kod necha tiyin qaytaradi?

Javob

35070. split(",") → ["350", "7"]. "7".padEnd(2, "0") → "70". 350 * 100 + 70 = 35070. Ya'ni 350 so'm 70 tiyin — to'g'ri, chunki 350,7 va 350,70 bir xil summa.

4. Yaxlitlash qoidalari

4.1 Qachon yaxlitlash kerak?

Tiyinda qo'shish, ayirish va butun songa ko'paytirish har doim butun natija beradi. Lekin foiz yoki bo'lish kasr tiyin beradi: 1 tiyinning uchdan biri. Bunday tiyin yo'q — yaxlitlash majburiy.

Savol faqat qanday qoida bilan. Bu dasturchi emas, biznes qarori: buxgalteriya, shartnoma yoki qonun belgilaydi. Dasturchining vazifasi — qoidani aniq bilish va uni kodda aniq yozish.

4.2 Asosiy strategiyalar

Qiymat Yuqoriga (Math.round) Noldan uzoqqa Bank usuli
2.5 3 3 2
3.5 4 4 4
-2.5 -2 -3 -2
2.4 / 2.6 2 / 3 2 / 3 2 / 3

Farq faqat aynan o'rtada, .5 da ko'rinadi:

  • Yuqoriga (Math.round) — Math darsidan: .5 doim katta tomonga. Manfiy summada kutilmagan natija beradi: -2.5 → -2.
  • Noldan uzoqqa (half away from zero) — maktabdagi qoida, musbat va manfiyda bir xil: 2.5 → 3, -2.5 → -3.
  • Bank usuli (banker's rounding, half to even) — .5 ni eng yaqin juft songa: 2.5 → 2, 3.5 → 4.

Bank usuli nega kerak? Yuqoriga yaxlitlashda .5 holatlar doim bir tomonga suriladi. Million amalda bu tizimli "ortiqcha" to'planadi. Bank usulida .5 larning yarmi yuqoriga, yarmi pastga ketadi va yig'indi muvozanatda qoladi. Shuning uchun buxgalteriya va bank tizimlarida ko'p ishlatiladi.

4.3 Kodda

Noldan uzoqqa yaxlitlash — Math darsidagi abs va sign bilan:

js
const qaytarish = -250.5; // mijozga qaytariladigan tiyin

const yuqoriga = Math.round(qaytarish);
const noldanUzoq =
  Math.sign(qaytarish) * Math.round(Math.abs(qaytarish));

console.log(yuqoriga); // -250
console.log(noldanUzoq); // -251

Mantiq: ishorani vaqtincha olib tashlaymiz (abs), musbat sonni yaxlitlaymiz, ishorani qaytaramiz (sign).

Bank usuli biroz uzunroq. Hozircha ternary bilan yozamiz:

js
const x = 2.5; // yaxlitlanadigan tiyin

const butun = Math.floor(x);
const kasr = x - butun;
const juftmi = butun % 2 === 0;

const bank =
  kasr > 0.5 ? butun + 1
  : kasr < 0.5 ? butun
  : juftmi ? butun : butun + 1;

console.log(bank); // 2

x ni 3.5, 2.4, 2.6 ga o'zgartirib ko'ring — jadvaldagi natijalar chiqadi. Keyinchalik funksiyalarni o'rgansangiz, bunday kodni bir marta yozib, hamma joyda chaqirasiz.

Diqqat: Yaxlitlashni kam va aniq joylarda qiling. Har oraliq qadamni yaxlitlasangiz, xatolar to'planadi. Odatda qoida: har bir foiz yoki bo'lishdan keyin darhol, bir marta, belgilangan strategiya bilan.

5. Foiz va chegirma

Kiyim do'konida 89 990 so'mlik ko'ylakka 15% chegirma. Hammasini tiyinda hisoblaymiz va foizni butun son sifatida saqlaymiz (0.15 emas, 15):

js
const narx = 8_999_000; // 89 990 so'm, tiyinda
const foiz = 15;

const chegirma = Math.round((narx * foiz) / 100);
const tolov = narx - chegirma;

console.log(chegirma); // 1349850
console.log(tolov); // 7649150

Mijoz 76 491,50 so'm to'laydi. E'tibor bering: tolov ni narx * 0.85 deb emas, narx - chegirma deb hisobladik. Shunda chegirma + tolov doim aniq narx ga teng — bir tiyin ham "yo'qolmaydi".

Foiz kasrli bo'lsa-chi, masalan 12,5%? Uni bazis punktda saqlang: 1 bazis punkt = 0,01%. 12,5% = 1250 bazis punkt, va hisob narx * 1250 / 10000. Banklar kredit va omonat foizlarini aynan shunday saqlaydi.

Tekshirib ko'ring: Nega const foiz = 0.15 emas, 15 saqlash yaxshiroq?

Javob

0.15 — kasr son, u ikkilik tizimda aniq saqlanmaydi. narx * 0.15 ba'zan ...0000005 kabi "dum" beradi (45500 * 0.07 misolini eslang). 15 esa butun son: narx * 15 aniq, keyin bitta bo'lish va bitta yaxlitlash.

6. QQS 12%

O'zbekistonda qo'shilgan qiymat solig'i (QQS) — 12%. Hisoblashning ikki holati bor.

6.1 Narxga QQS qo'shish

Narx QQS'siz berilgan (masalan, ulgurji narx). QQS ustiga qo'shiladi:

js
const sofNarx = 11_500_000; // 115 000 so'm, QQS'siz

const qqs = Math.round((sofNarx * 12) / 100);
const jami = sofNarx + qqs;

console.log(qqs); // 1380000
console.log(jami); // 12880000

6.2 Narx ichidan QQS'ni ajratish

Chakana narx odatda QQS bilan yoziladi. Chekda "shu jumladan QQS 12%" degan qator bor — ya'ni narx ichidagi QQS ulushi. 129 000 so'mlik mahsulotda QQS qancha?

Xato yo'l — 129000 * 0.12. Narx QQS bilan birga 112% ni tashkil qiladi, sof narx — 100%, QQS — 12%. Demak QQS = narx × 12 / 112:

js
const narx = 12_900_000; // 129 000 so'm, QQS bilan

const qqs = Math.round((narx * 12) / 112);
const sofNarx = narx - qqs;

console.log((narx * 12) / 112); // 1382142.857142857
console.log(qqs); // 1382143
console.log(sofNarx); // 11517857

QQS 13 821,43 so'm. Yana o'sha hiyla: sofNarx ni alohida bo'lish bilan emas, ayirish bilan topdik. Shunda sofNarx + qqs aniq narx ga teng.

6.3 Har qatorda yoki jamida?

Chekda ikki mahsulot: choy 5 000 so'm va non 8 500 so'm. QQS'ni har mahsulot uchun alohida yaxlitlash va jamidan hisoblash — har xil natija beradi:

js
const choy = 500_000;
const non = 850_000;

const qatorlab =
  Math.round((choy * 12) / 112) + Math.round((non * 12) / 112);
const jamidan = Math.round(((choy + non) * 12) / 112);

console.log(qatorlab); // 144642
console.log(jamidan); // 144643

Bir tiyin farq! Ikkala usul ham matematik jihatdan "to'g'ri", faqat yaxlitlash har xil joyda. Qaysi biri kerakligini soliq qoidasi va kompaniya buxgalteriyasi belgilaydi. Dasturchi uchun muhimi — bitta usulni tanlab, hamma joyda izchil qo'llash. Aks holda chekdagi va hisobotdagi QQS mos kelmaydi.

7. Hisobni bo'lish

Uch do'st kafeda 100 000 so'mlik hisobni teng bo'lishmoqchi. 100000 / 3 — 33333.333.... Har kim 33 333 so'm to'lasa, jami 99 999 bo'ladi — bir so'm yetmaydi.

To'g'ri usul: butun qismni hammaga beramiz, qoldiqni esa birinchi odamlarga bittadan taqsimlaymiz. Arifmetika darsidagi % qoldiq operatori yordam beradi:

js
const hisob = 100_000;
const odamlar = 3;

const ulush = Math.floor(hisob / odamlar);
const qoldiq = hisob % odamlar;

console.log(ulush); // 33333
console.log(qoldiq); // 1

Natija: birinchi odam ulush + 1 = 33 334 so'm, qolgan ikkitasi 33 333 so'mdan. Jami aniq 100 000. Qoldiq doim odamlar sonidan kichik, shuning uchun hech kim boshqalardan 1 so'mdan ortiq to'lamaydi.

Ulushlar teng bo'lmasa-chi? Masalan, sheriklar foydani 70/30 bo'lishadi. Yana ayirish hiylasi — oxirgi ulushni "qolganicha" beramiz:

js
const foyda = 99_999;

const birinchi = Math.round((foyda * 70) / 100);
const ikkinchi = foyda - birinchi;

console.log(birinchi); // 69999
console.log(ikkinchi); // 30000

69999.3 yaxlitlandi, ikkinchisi esa qolganini oldi. Ikkalasini qo'shsangiz — aniq 99 999. Bu naqsh inglizcha allocation (taqsimlash) deyiladi va pul kutubxonalarida alohida funksiya sifatida bor.

Tekshirib ko'ring: 50 000 so'mni 7 kishiga bo'lsak, ulush va qoldiq qancha? Nechta odam 1 so'm ko'proq to'laydi?

Javob

ulush = 7142, qoldiq = 6. 7142 × 7 = 49994, yetmagan 6 so'm — 6 kishiga bittadan. Ya'ni 6 kishi 7 143 so'm, bitta kishi 7 142 so'm to'laydi. Jami: 6 × 7143 + 7142 = 50000.

8. So'mni chiroyli ko'rsatish: Intl.NumberFormat

Math darsida Intl.NumberFormat bilan minglarni ajratishni ko'rgandik. Endi valyuta bilan:

js
const somFormat = new Intl.NumberFormat("uz-UZ", {
  style: "currency",
  currency: "UZS",
});

console.log(somFormat.format(12000)); // 12 000,00 soʻm
console.log(somFormat.format(1250050 / 100)); // 12 500,50 soʻm

Jingalak qavs ichidagi style: "currency", currency: "UZS" — formatlovchiga beriladigan sozlamalar: "valyuta sifatida ko'rsat, valyuta — so'm". Bu yozuv shakli obyekt deyiladi, uni keyinroq to'liq o'rganamiz. UZS — so'mning xalqaro kodi.

Yuqoridagi natijalar Node 22 da haqiqatan chiqqan. Endi ularga yaqinroq qaraymiz — ikki kutilmagan narsa bor:

js
const somFormat = new Intl.NumberFormat("uz-UZ", {
  style: "currency",
  currency: "UZS",
});
const matn = somFormat.format(12000);

console.log(matn.includes(" ")); // false
console.log(matn.includes("'")); // false
console.log(matn.codePointAt(2).toString(16)); // a0
console.log(matn.codePointAt(12).toString(16)); // 2bb
  • Minglar orasida oddiy bo'sh joy yo'q. U yerda Matn ↔ son darsida ko'rgan uzilmas bo'sh joy turibdi (kodi U+00A0).
  • so'm dagi belgi — oddiy apostrof emas, ʻ (kodi U+02BB). Bu o'zbek lotin alifbosining rasmiy "o'" belgisi. codePointAt ni Unicode darsida ko'rgandik.

Oqibati:

js
const somFormat = new Intl.NumberFormat("uz-UZ", {
  style: "currency",
  currency: "UZS",
});

console.log(somFormat.format(12000) === "12 000,00 so'm"); // false
console.log(Number(somFormat.format(12000))); // NaN

Qoida: formatlangan matn — faqat ko'rsatish uchun. Uni boshqa satr bilan solishtirmang, testlarda qo'lda yozilgan satrga tenglashtirmang va qaytarib songa aylantirmang. Pul doim tiyinda, butun son holida saqlanadi.

Tiyinsiz ko'rsatish uchun maximumFractionDigits: 0 sozlamasi bor:

js
const somFormat = new Intl.NumberFormat("uz-UZ", {
  style: "currency",
  currency: "UZS",
  maximumFractionDigits: 0,
});

console.log(somFormat.format(12000)); // 12 000 soʻm

Boshqa tilda formatlasak, natija butunlay boshqacha:

Til kodi format(12000) natijasi
"uz-UZ" 12 000,00 soʻm
"ru-RU" 12 000,00 UZS
"en-US" UZS 12,000.00

Diqqat: Formatlash natijasi Node va brauzer versiyasiga bog'liq. Til qoidalari ICU degan xalqaro ma'lumotlar bazasidan olinadi va u vaqti-vaqti bilan yangilanadi. Boshqa versiyada soʻm o'rniga so'm yoki UZS chiqishi mumkin. Bu ham formatlangan matnga tayanmaslikka yana bir sabab. Batafsil — Intl.NumberFormat darsida.

9. Kutubxonalar: qachon tiyin yetmaydi

Tiyin usuli do'kon, kafe, yetkazib berish va obunalar uchun yetarli. Lekin ba'zi hisoblar murakkabroq: kredit foizini kunlab hisoblash, valyuta kursi 4–6 xonali kasr bilan, investitsiya ulushlari. Bunday joyda decimal kutubxonalar ishlatiladi. Ular sonni o'nlik tizimda saqlaydi va 0.1 + 0.2 ni aniq 0.3 qiladi.

Kutubxona — boshqa dasturchilar yozgan tayyor kod, uni loyihaga npm (JavaScript paketlari "do'koni") orqali qo'shasiz. Npm'ni kursda alohida o'rganamiz, hozir nomlarini bilib qo'ying:

  • decimal.js (10-versiya) — eng to'liq: aniqlik va yaxlitlash rejimini sozlash, daraja, ildiz.
  • big.js (7-versiya) — o'sha muallifning kichik va sodda varianti: faqat asosiy amallar.
  • dinero.js (2-versiya) — sonni emas, pulni ifodalaydi: summa va valyuta birga, taqsimlash (allocation) tayyor.

Ma'lumotlar bazasida ham xuddi shu tamoyil: pul NUMERIC (aniq o'nlik) yoki BIGINT (tiyinda) ustunida saqlanadi, kasr turida emas. Buni SQL qismida ko'rasiz.

10. Hujumchi nigohi

To'lov bor joyda buzishga urinish ham bor. Eng ko'p uchraydigan hujumlar:

  • Narxni brauzerdan olish. Hujumchi sahifadagi narxni 89 990 dan 1 so'mga o'zgartirib, serverga yuboradi. Himoya: server narxni hech qachon brauzerdan olmaydi. U faqat mahsulot ID si va sonini oladi, narxni o'z bazasidan o'qiydi.
  • Manfiy son. Savatchada -3 ta mahsulot — jami manfiy, ya'ni do'kon mijozga pul to'laydi. Himoya: oldingi darsdagi Number.isInteger(soni) && soni > 0.
  • Kasr tiyin bilan o'ynash. Hujumchi 0,005 so'mlik minglab o'tkazma qiladi. Har biri yuqoriga yaxlitlanib 1 tiyin bo'lsa, u "bo'sh joydan" pul yasaydi. Himoya: kiritilgan summa tiyinda butun bo'lishi shart, kasr qism rad etiladi.
  • NaN va Infinity. "1e999" summasi Infinity ga aylanib, hisob-kitobni buzadi. Himoya: Number.isSafeInteger(tiyin).

Hammasi serverda qayta tekshiriladi — brauzer tekshiruvi faqat qulaylik uchun.

11. Ko'p uchraydigan xatolar

11.1 Pulni toFixed bilan "tuzatish"

(0.1 + 0.2).toFixed(2) — "0.30". Ko'rinishi to'g'ri, lekin bu satr. Undan keyin hisoblasangiz, yopishtirish chiqadi. Qolaversa, toFixed ham adashadi: 1.005-bob.toFixed(2) — "1.00". Yechim — butun tiyin.

11.2 So'mdan tiyinga Math.floor bilan o'tish

Math.floor(1.15 * 100) — 114. Faqat Math.round.

11.3 Qismlarni alohida yaxlitlab, jamini tekshirmaslik

Hisobni uchga bo'lib, har birini yaxlitlasangiz, jami asl summaga teng bo'lmaydi. Doim oxirgi qismni ayirish bilan toping yoki qoldiqni taqsimlang.

11.4 Formatlangan satrni solishtirish

format(12000) === "12 000,00 so'm" — false. Solishtirish — faqat tiyindagi butun sonlar bilan.

11.5 Foizni kasr bilan saqlash

narx * 0.07 o'rniga narx * 7 / 100, keyin bitta yaxlitlash.

12. Mashqlar

1-mashq (oson): Savatcha

Savatchada: 2 ta sut (9 900 so'm), 3 ta non (4 500 so'm) va 1 ta pishloq (38 750,50 so'm). Narxlarni tiyinda yozib, jamini tiyinda hisoblang. Keyin (jami / 100).toFixed(2) bilan so'mda chiqaring.

Yechim
js
const sut = 990_000;
const non = 450_000;
const pishloq = 3_875_050;

const jami = sut * 2 + non * 3 + pishloq;

console.log(jami); // 7205050
console.log((jami / 100).toFixed(2)); // 72050.50

Hamma amal butun sonlar bilan — natija aniq. So'mga faqat eng oxirida, ko'rsatish uchun o'tdik.

2-mashq (o'rta): Chegirma va QQS

Televizor narxi — 4 990 000 so'm (QQS bilan). Aksiyada 20% chegirma. Hisoblang (hammasi tiyinda):

  1. chegirma va tolov (chegirmadan keyingi narx);
  2. tolov ichidagi QQS 12% va sof narx.

Tekshiring: tolov + chegirma narxga teng, sofNarx + qqs esa tolov ga teng bo'lsin.

Ishora: 5- va 6.2-bo'limlardagi "ayirish hiylasi". Katta sonlarni 4_990_000 kabi yozing — Son yozish shakllari.

Yechim
js
const narx = 499_000_000; // 4 990 000 so'm, tiyinda

const chegirma = Math.round((narx * 20) / 100);
const tolov = narx - chegirma;

const qqs = Math.round((tolov * 12) / 112);
const sofNarx = tolov - qqs;

console.log(chegirma); // 99800000
console.log(tolov); // 399200000
console.log(qqs); // 42771429
console.log(sofNarx); // 356428571
console.log(tolov + chegirma === narx); // true
console.log(sofNarx + qqs === tolov); // true

Mijoz 3 992 000 so'm to'laydi, uning ichida QQS 427 714,29 so'm. (tolov * 12) / 112 — 42771428.57..., yaxlitlab 42771429 tiyin.

3-mashq (qiyin): Taksi hisobini bo'lish

Uch hamkasb taksida 87 350 so'mlik yo'l haqini bo'lishmoqchi. Ilova "tiyingacha adolatli" bo'lishi kerak:

  1. Summani tiyinda yozing.
  2. ulush va qoldiq ni toping.
  3. Birinchi qoldiq ta odam ulush + 1 tiyin to'laydi — uni katta deb nomlang. Ikki xil ulushni so'mda (toFixed(2)) chiqaring.
  4. Oxirida tekshiring: katta * qoldiq + ulush * (odamlar - qoldiq) aniq umumiy summaga teng — true chiqishi kerak.
Yechim
js
const summa = 8_735_000; // 87 350 so'm, tiyinda
const odamlar = 3;

const ulush = Math.floor(summa / odamlar);
const qoldiq = summa % odamlar;
const katta = ulush + 1;

console.log(ulush); // 2911666
console.log(qoldiq); // 2
console.log((katta / 100).toFixed(2)); // 29116.67
console.log((ulush / 100).toFixed(2)); // 29116.66

const tekshir = katta * qoldiq + ulush * (odamlar - qoldiq);
console.log(tekshir === summa); // true

Ikki kishi 29 116,67 so'm, bittasi 29 116,66 so'm to'laydi. Jami — aniq 87 350 so'm.

odamlar ni 4 ga o'zgartirib ko'ring. Bu safar qoldiq = 0: summa to'rtga qoldiqsiz bo'linadi, hamma 21 837,50 so'm to'laydi. Tekshiruv yana true — formula qoldiq bo'lmaganda ham to'g'ri ishlaydi.

13. Real ishda

  • To'lov tizimlari: Payme, Click va Telegram to'lovlari bilan ishlaganda summani tiyinda yuborish — birinchi va eng ko'p uchraydigan talab. To'lov ekotizimi darsida real integratsiya qilasiz.
  • Onlayn do'kon va chek: chegirma, promo-kod, QQS, yetkazish narxi — hammasi tiyinda, ayirish hiylasi bilan.
  • Buxgalteriya va bank: yaxlitlash strategiyasi hujjatda yozilgan bo'ladi. Dasturchi uni aynan bajaradi.
  • Intervyu: "0.1 + 0.2 nega 0.3 emas va pulni qanday saqlaysiz?" — frontend va backend intervyularidagi eng mashhur savollardan biri. Kutilgan javob: "eng kichik birlikda butun son yoki decimal kutubxona".

Xulosa

  • Pul uchun kasr son (number dagi 0.1, 1.12) xavfli: 72500 * 1.12 — 81200.00000000001.
  • Pulni tiyinda, butun son sifatida saqlang. So'mdan tiyinga — faqat Math.round(som * 100), satrdan esa kasr sonsiz.
  • Foiz va bo'lishdan keyin bir marta, biznes belgilagan qoida bilan yaxlitlang: yuqoriga, noldan uzoqqa yoki bank usuli.
  • Oxirgi qismni ayirish bilan toping (narx - chegirma, foyda - birinchi) — shunda bir tiyin ham yo'qolmaydi.
  • QQS narx ichidan: narx * 12 / 112. Qatorlab yoki jamidan — bittasini tanlab, izchil qo'llang.
  • Intl.NumberFormat natijasi — faqat ko'rsatish uchun: unda uzilmas bo'sh joy va ʻ bor.

Keyingi dars: BigInt: juda katta butun sonlar — MAX_SAFE_INTEGER dan katta sonlar bilan aniq ishlash va uning oddiy sonlar bilan aralashmasligi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
JavaScript'da pul hisoblash: tiyinda saqlash, yaxlitlash, chegirma va QQS — IlmHamroh