17-bo‘lim
Standart kutubxona
Vaqt, sana, fayl tizimi, tasodifiy sonlar va formatlash - tashqi kutubxonasiz.
Ushbu bo‘lim mundarijasi
C++ standart kutubxonasi konteynerlar va algoritmlardan iborat emas. Unda vaqt hisobi, sana kalendari, fayl tizimi va yuqori sifatli tasodifiy sonlar generatorlari ham bor - hech qanday tashqi bog'liqliksiz.
std::chrono - vaqt oralig'i #
#include <print>
#include <string>
#include <vector>
#include <chrono>
#include <filesystem>
#include <fstream>
#include <random>
#include <numeric>
#include <algorithm>
using namespace std::chrono;
int main()
{
// Vaqt oraliqlari - TURLI, aralashtirib bo'lmaydi
seconds soniya{90};
minutes daqiqa{5};
hours soat{2};
std::println("90 soniya = {}", soniya);
std::println("5 daqiqa = {}", daqiqa);
std::println("2 soat = {}", soat);
std::println("");
std::println("Avtomatik aylantirish (aniqlik yo'qolmasa):");
seconds jami = soniya + daqiqa + soat;
std::println(" yig'indi: {}", jami);
std::println("");
std::println("Aniqlik yo'qoladigan aylantirish OSHKORA bo'lishi kerak:");
auto daqiqada = duration_cast<minutes>(jami);
std::println(" duration_cast<minutes>: {}", daqiqada);
std::println(" (kasr qismi tashlandi)");
std::println("");
std::println("Kasrli aylantirish:");
auto aniq = duration<double, std::ratio<60>>(jami);
std::println(" {:.4f} daqiqa", aniq.count());
std::println("");
std::println("Literal qo'shimchalari:");
using namespace std::chrono_literals;
auto kun = 24h;
auto hafta = 7 * kun;
std::println(" 24h = {}", kun);
std::println(" 7 * 24h = {}", hafta);
std::println(" hafta soniyada = {}", duration_cast<seconds>(hafta));
return 0;
}
90 soniya = 90s
5 daqiqa = 5min
2 soat = 2h
Avtomatik aylantirish (aniqlik yo'qolmasa):
yig'indi: 7590s
Aniqlik yo'qoladigan aylantirish OSHKORA bo'lishi kerak:
duration_cast<minutes>: 126min
(kasr qismi tashlandi)
Kasrli aylantirish:
126.5000 daqiqa
Literal qo'shimchalari:
24h = 24h
7 * 24h = 168h
hafta soniyada = 604800s
chrono - kuchli turlarning eng yaxshi namunasiint soniya = 90; va seconds soniya{90}; orasidagi
farq katta.
Birinchisi bilan bu xato kompilyatsiya qilinadi:
int kutish = 5; // daqiqami, soniyami?
uxla(kutish); // kim biladi
Ikkinchisi bilan esa:
uxla(5min); // aniq
uxla(5s); // ham aniq
uxla(5); // KOMPILYATSIYA XATOSI
chrono avtomatik aylantiradi, lekin faqat
aniqlik yo'qolmasa:
| Aylantirish | Avtomatikmi |
|---|---|
minutes → seconds | Ha |
seconds → minutes | Yo'q - duration_cast kerak |
hours → milliseconds | Ha |
milliseconds → seconds | Yo'q |
Bu aynan biz 13-bo'limda Pul turi bilan qilgan ish -
faqat standart kutubxona darajasida.
Sana va kalendar (C++20) #
using namespace std::chrono;
int main()
{
// Sana - kalendar turi
year_month_day mustaqillik{2024y, September, 1d};
std::println("sana: {}", mustaqillik);
std::println("yil: {}", static_cast<int>(mustaqillik.year()));
std::println("oy: {}", static_cast<unsigned>(mustaqillik.month()));
std::println("kun: {}", static_cast<unsigned>(mustaqillik.day()));
std::println("");
std::println("to'g'ri sanami: {}", mustaqillik.ok());
year_month_day yomon{2023y, February, 30d};
std::println("2023-02-30 to'g'rimi: {}", yomon.ok());
std::println("");
// Hafta kuni
weekday kun{sys_days{mustaqillik}};
std::println("2024-09-01 hafta kuni: {}", kun);
std::println("");
std::println("Sanalar farqi:");
year_month_day boshlanish{2024y, January, 1d};
auto kunlar = sys_days{mustaqillik} - sys_days{boshlanish};
std::println(" 1-yanvardan 1-sentyabrgacha: {}", kunlar);
std::println("");
std::println("Kabisa yillar:");
for (int y : {2020, 2023, 2024, 2100, 2000}) {
std::println(" {} kabisami: {}", y, year{y}.is_leap());
}
std::println("");
std::println("Oyning oxirgi kuni:");
for (auto oy : {January, February, April}) {
year_month_day_last oxirgi{2024y, month_day_last{oy}};
std::println(" {} 2024: {} kun", oy,
static_cast<unsigned>(oxirgi.day()));
}
return 0;
}
sana: 2024-09-01
yil: 2024
oy: 9
kun: 1
to'g'ri sanami: true
2023-02-30 to'g'rimi: false
2024-09-01 hafta kuni: Sun
Sanalar farqi:
1-yanvardan 1-sentyabrgacha: 244d
Kabisa yillar:
2020 kabisami: true
2023 kabisami: false
2024 kabisami: true
2100 kabisami: false
2000 kabisami: true
Oyning oxirgi kuni:
Jan 2024: 31 kun
Feb 2024: 29 kun
Apr 2024: 30 kun
C++20 gacha sana bilan ishlash uchun boost::date_time
yoki qo'lda yozilgan kod kerak edi. <ctime> esa C
merosi - xavfsiz emas va lokal holatga bog'liq.
Asosiy turlar:
| Tur | Nima |
|---|---|
year, month, day | Alohida qismlar |
year_month_day | To'liq sana |
weekday | Hafta kuni |
sys_days | Kunlar sonidagi sana (arifmetika uchun) |
hh_mm_ss | Kun ichidagi vaqt |
zoned_time | Vaqt mintaqasi bilan |
Naqsh: kalendar turlari o'qish uchun, sys_days
hisoblash uchun.
ok() metodi sanani tekshiradi - 2023-02-30 kabi
mavjud bo'lmagan sanalar yaratilishi mumkin, lekin
ok() false qaytaradi.
Vaqtni o'lchash #
using namespace std::chrono;
long long ogirIsh(int n)
{
long long jami = 0;
for (int i = 1; i <= n; ++i) jami += static_cast<long long>(i) * i;
return jami;
}
int main()
{
auto boshlanish = steady_clock::now();
long long natija = ogirIsh(2'000'000);
auto tugash = steady_clock::now();
auto ketgan = duration_cast<microseconds>(tugash - boshlanish);
std::println("natija: {}", natija);
std::println("hisoblash bajarildi");
std::println("vaqt musbatmi: {}", ketgan.count() >= 0);
std::println("bir soniyadan kammi: {}", ketgan < 1s);
std::println("");
std::println("Uch xil soat:");
std::println(" steady_clock - o'lchash uchun, ORQAGA KETMAYDI");
std::println(" system_clock - haqiqiy sana/vaqt, sozlanishi mumkin");
std::println(" high_resolution_clock - odatda steady_clock ning taxallusi");
std::println("");
std::println("steady_clock monotonmi: {}", steady_clock::is_steady);
std::println("system_clock monotonmi: {}", system_clock::is_steady);
return 0;
}
natija: 2666668666667000000
hisoblash bajarildi
vaqt musbatmi: true
bir soniyadan kammi: true
Uch xil soat:
steady_clock - o'lchash uchun, ORQAGA KETMAYDI
system_clock - haqiqiy sana/vaqt, sozlanishi mumkin
high_resolution_clock - odatda steady_clock ning taxallusi
steady_clock monotonmi: true
system_clock monotonmi: false
steady_clock ishlatingsystem_clock foydalanuvchi yoki NTP xizmati
tomonidan o'zgartirilishi mumkin - hatto orqaga.
Agar o'lchov o'rtasida shunday bo'lsa, manfiy davomiylik
olasiz.
steady_clock esa faqat oldinga ketadi. U haqiqiy
sanani bilmaydi - lekin bizga u kerak emas.
| Vazifa | Soat |
|---|---|
| "Qancha vaqt ketdi" | steady_clock |
| "Hozir soat nechchi" | system_clock |
| Taymaut | steady_clock |
| Fayl vaqti | file_clock |
Bu misolda biz ketgan vaqtni chop etmadik - faqat uning musbat va bir soniyadan kam ekanini tekshirdik. Sabab: aniq raqam har ishga tushirishda boshqacha bo'ladi va bu darslikning barcha misollari takrorlanadigan bo'lishi kerak.
O'zingizning o'lchovlaringizda albatta raqamni chop eting - lekin bir necha marta o'lchab, o'rtachasini oling.
std::filesystem #
namespace fs = std::filesystem;
int main()
{
fs::path asos{"/tmp/sr_cpp_17"};
// Tozalab boshlaymiz
fs::remove_all(asos);
fs::create_directories(asos / "hujjatlar" / "2024");
// Fayllar yaratamiz
for (const auto& [nom, matn] : std::vector<std::pair<std::string, std::string>>{
{"hujjatlar/oqish.txt", "Birinchi fayl"},
{"hujjatlar/2024/hisobot.txt", "Yillik hisobot matni"},
{"sozlama.json", "{}"},
}) {
std::ofstream f{asos / nom};
f << matn;
}
std::println("Yo'l qismlari:");
fs::path p = asos / "hujjatlar" / "2024" / "hisobot.txt";
std::println(" to'liq: {}", p.string());
std::println(" ota katalog: {}", p.parent_path().string());
std::println(" fayl nomi: {}", p.filename().string());
std::println(" kengaytma: {}", p.extension().string());
std::println(" kengaytmasiz:{}", p.stem().string());
std::println("");
std::println("Tekshiruvlar:");
std::println(" mavjudmi: {}", fs::exists(p));
std::println(" oddiy fayl: {}", fs::is_regular_file(p));
std::println(" katalogmi: {}", fs::is_directory(p));
std::println(" hajmi: {} bayt", fs::file_size(p));
std::println("");
std::println("Rekursiv aylanish:");
std::vector<std::string> topilgan;
for (const auto& yozuv : fs::recursive_directory_iterator(asos)) {
std::string turi = yozuv.is_directory() ? "katalog" : "fayl";
topilgan.push_back(std::format("{:<8} {}", turi,
fs::relative(yozuv.path(), asos).string()));
}
std::ranges::sort(topilgan);
for (const auto& s : topilgan) std::println(" {}", s);
std::println("");
std::println("Faqat .txt fayllar:");
int soni = 0;
std::uintmax_t jamiHajm = 0;
for (const auto& yozuv : fs::recursive_directory_iterator(asos)) {
if (yozuv.is_regular_file() && yozuv.path().extension() == ".txt") {
++soni;
jamiHajm += yozuv.file_size();
}
}
std::println(" {} ta fayl, jami {} bayt", soni, jamiHajm);
fs::remove_all(asos);
std::println("");
std::println("tozalandi, mavjudmi: {}", fs::exists(asos));
return 0;
}
Yo'l qismlari:
to'liq: /tmp/sr_cpp_17/hujjatlar/2024/hisobot.txt
ota katalog: /tmp/sr_cpp_17/hujjatlar/2024
fayl nomi: hisobot.txt
kengaytma: .txt
kengaytmasiz:hisobot
Tekshiruvlar:
mavjudmi: true
oddiy fayl: true
katalogmi: false
hajmi: 20 bayt
Rekursiv aylanish:
fayl hujjatlar/2024/hisobot.txt
fayl hujjatlar/oqish.txt
fayl sozlama.json
katalog hujjatlar
katalog hujjatlar/2024
Faqat .txt fayllar:
2 ta fayl, jami 33 bayt
tozalandi, mavjudmi: false
path ni satr sifatida yig'ishtirmangstd::string yol = katalog + "/" + nom; // YOMON
fs::path yol = fs::path{katalog} / nom; // YAXSHI
operator/ platformaga mos ajratgichni qo'yadi va
takroriy // ni oldini oladi.
Foydali metodlar:
| Metod | Nima qaytaradi |
|---|---|
filename() | hisobot.txt |
stem() | hisobot |
extension() | .txt |
parent_path() | Ota katalog |
is_absolute() | Mutlaq yo'lmi |
lexically_normal() | .. va . ni yechadi |
Diqqat: fs funksiyalari xato holatida istisno
tashlaydi. Istisnosiz variant ham bor:
std::error_code xato;
auto hajm = fs::file_size(p, xato);
if (xato) { ... }
Fayl tizimi bilan ishlaganda poyga holati doim mavjud:
exists() va ochish orasida fayl o'chirilishi mumkin.
Shuning uchun ochishga urinib ko'rish ko'pincha
tekshirishdan yaxshiroq.
std::random #
int main()
{
// Takrorlanadigan urug' - sinov uchun
std::mt19937 generator{20240901u};
std::println("Bir xil urug' - bir xil ketma-ketlik:");
std::uniform_int_distribution<int> zar{1, 6};
std::print(" zarlar:");
for (int i = 0; i < 10; ++i) std::print(" {}", zar(generator));
std::println("");
std::mt19937 ikkinchi{20240901u};
std::print(" qayta: ");
for (int i = 0; i < 10; ++i) std::print(" {}", zar(ikkinchi));
std::println("");
std::println("");
std::println("Turli taqsimotlar:");
std::mt19937 g{42u};
std::uniform_real_distribution<double> tekis{0.0, 1.0};
std::print(" tekis [0,1):");
for (int i = 0; i < 4; ++i) std::print(" {:.5f}", tekis(g));
std::println("");
std::normal_distribution<double> normal{100.0, 15.0};
std::print(" normal (100,15):");
for (int i = 0; i < 4; ++i) std::print(" {:.3f}", normal(g));
std::println("");
std::bernoulli_distribution tanga{0.5};
std::print(" tanga:");
for (int i = 0; i < 8; ++i) std::print(" {}", tanga(g) ? "O" : "P");
std::println("");
std::println("");
std::println("Zar taqsimoti tekshiruvi (60000 tashlash):");
std::mt19937 sinov{7u};
std::vector<int> hisob(7, 0);
for (int i = 0; i < 60'000; ++i) ++hisob[static_cast<std::size_t>(zar(sinov))];
for (int yuz = 1; yuz <= 6; ++yuz) {
double foiz = 100.0 * hisob[static_cast<std::size_t>(yuz)] / 60'000.0;
bool meyorda = foiz > 16.0 && foiz < 17.4;
std::println(" {} yuzi: {:>5} marta ({:.2f}%) meyorda: {}",
yuz, hisob[static_cast<std::size_t>(yuz)], foiz, meyorda);
}
std::println("");
std::println("jami: {}", std::accumulate(hisob.begin(), hisob.end(), 0));
return 0;
}
Bir xil urug' - bir xil ketma-ketlik:
zarlar: 4 2 2 3 6 6 4 3 1 1
qayta: 4 2 2 3 6 6 4 3 1 1
Turli taqsimotlar:
tekis [0,1): 0.79654 0.18343 0.77969 0.59685
normal (100,15): 86.248 98.138 69.836 92.608
tanga: O P O P P O P P
Zar taqsimoti tekshiruvi (60000 tashlash):
1 yuzi: 10138 marta (16.90%) meyorda: true
2 yuzi: 9960 marta (16.60%) meyorda: true
3 yuzi: 9832 marta (16.39%) meyorda: true
4 yuzi: 9989 marta (16.65%) meyorda: true
5 yuzi: 10162 marta (16.94%) meyorda: true
6 yuzi: 9919 marta (16.53%) meyorda: true
jami: 60000
rand() ni ishlatmangC dan meros qolgan rand() uch sababdan yaroqsiz:
| Muammo | Izoh |
|---|---|
| Sifati past | Ba'zi amalga oshirishlarda davri juda qisqa |
% n siljish beradi | Diapazon teng taqsimlanmaydi |
| Global holat | Ko'p oqimda xavfsiz emas |
rand() % 6 + 1 klassik xato: RAND_MAX 6 ga
bo'linmasa, kichik raqamlar ko'proq chiqadi.
To'g'ri naqsh - generator va taqsimot alohida:
std::mt19937 g{urug}; // generator
std::uniform_int_distribution<int> zar{1, 6}; // taqsimot
int natija = zar(g);
Urug' tanlash:
| Maqsad | Urug' |
|---|---|
| Sinov, takrorlanish | Aniq son (42u) |
| Haqiqiy tasodifiylik | std::random_device{}() |
| Kriptografiya | Hech qaysisi - OS API ishlating |
Oxirgi qator muhim: mt19937 kriptografik jihatdan
xavfsiz emas. 624 ta chiqishni ko'rgan hujumchi
butun keyingi ketma-ketlikni tiklay oladi.
Formatlash imkoniyatlari #
int main()
{
std::println("Tekislash va kenglik:");
std::println(" [{:<12}] chapga", "matn");
std::println(" [{:>12}] o'ngga", "matn");
std::println(" [{:^12}] markazga", "matn");
std::println(" [{:*^12}] to'ldirgich bilan", "matn");
std::println("");
std::println("Sonlar:");
std::println(" [{:8.3f}] kasr aniqligi", 3.14159265);
std::println(" [{:+}] ishora majburiy", 42);
std::println(" [{:08.2f}] nol bilan to'ldirish", 3.5);
std::println(" [{:.0f}] yaxlitlash", 2.5);
std::println(" [{:.0f}] yaxlitlash", 3.5);
std::println("");
std::println("Sanoq sistemalari:");
int n = 255;
std::println(" o'nlik: {}", n);
std::println(" ikkilik: {:b}", n);
std::println(" sakkizlik: {:o}", n);
std::println(" o'n oltilik: {:x}", n);
std::println(" prefiks bn: {:#b}", n);
std::println(" prefiks 16: {:#x}", n);
std::println("");
std::println("Argument raqami bilan:");
std::println(" {0} - {1} - {0}", "takror", "o'rta");
std::println("");
std::println("Ichma-ich kenglik:");
for (int k : {6, 10, 14}) {
std::println(" [{:>{}}] kenglik {}", "x", k, k);
}
std::println("");
std::println("Konteynerlar (C++23):");
std::vector<int> v{1, 2, 3, 4};
std::println(" vector: {}", v);
std::println(" juftlik: {}", std::pair{1, "bir"});
return 0;
}
Tekislash va kenglik:
[matn ] chapga
[ matn] o'ngga
[ matn ] markazga
[****matn****] to'ldirgich bilan
Sonlar:
[ 3.142] kasr aniqligi
[+42] ishora majburiy
[00003.50] nol bilan to'ldirish
[2] yaxlitlash
[4] yaxlitlash
Sanoq sistemalari:
o'nlik: 255
ikkilik: 11111111
sakkizlik: 377
o'n oltilik: ff
prefiks bn: 0b11111111
prefiks 16: 0xff
Argument raqami bilan:
takror - o'rta - takror
Ichma-ich kenglik:
[ x] kenglik 6
[ x] kenglik 10
[ x] kenglik 14
Konteynerlar (C++23):
vector: [1, 2, 3, 4]
juftlik: (1, "bir")
Yuqoridagi chiqishda {:.0f} 2.5 ni 2 ga,
3.5 ni esa 4 ga yaxlitladi.
Bu xato emas - bu juftga yaxlitlash (IEEE 754 standarti). Aniq yarim bo'lganda eng yaqin juft songa yaxlitlanadi.
Sabab: har doim yuqoriga yaxlitlash uzoq ketma-ketlikda siljish to'playdi. Juftga yaxlitlash bu siljishni o'rtacha nolga tushiradi.
Moliyaviy hisob-kitobda bu muhim. Agar sizga boshqa qoida kerak bo'lsa - o'zingiz yozing:
double yarimYuqoriga(double q) {
return std::floor(q + 0.5);
}
Yana bir sabab kasr sonlarni pul uchun ishlatmaslik
kerakligi: 0.1 + 0.2 != 0.3. 13-bo'limdagi Pul
turi butun sonda tiyin saqlagani bejiz emas.
seconds,minutes,hoursni qo'shing - qaysi turga aylandi?duration_castsizsecondsdanminutesga o'ting - nima bo'ladi?year_month_daybilan sana yarating vaok()ni tekshiring.- Ikki sana orasidagi kunlarni hisoblang.
steady_clockbilan funksiya vaqtini o'lchang.fs::pathningstem(),extension(),parent_path()ni chiqaring.- Katalogni rekursiv aylanib
.txtfayllarni sanang. mt19937ni bir xil urug' bilan ikki marta ishga tushiring.- Zar taqsimotini 60 000 tashlash bilan tekshiring.
{:*^12},{:#x},{:>{}}formatlarini sinab ko'ring.
Xulosa #
chronovaqt oraliqlarini turga aylantiradi -secondsvaminutesaralashmaydi.- Aniqlik yo'qoladigan aylantirish oshkora
duration_casttalab qiladi. - C++20 kalendari (
year_month_day,weekday) tashqi kutubxonasiz sana hisobini beradi. - Kalendar turlari o'qish uchun,
sys_dayshisoblash uchun. - O'lchash uchun
steady_clock-system_clockorqaga ketishi mumkin. fs::pathnioperator/bilan yig'ing, satr birlashtirish bilan emas.fsfunksiyalari istisno tashlaydi;std::error_codevarianti ham bor.rand()o'rniga generator + taqsimot juftligini ishlating.- Bir xil urug' - bir xil ketma-ketlik; bu sinovlar uchun zarur.
mt19937kriptografik jihatdan xavfsiz emas.std::formatkenglik, aniqlik, sanoq sistemasi va ichma-ich parametrlarni qo'llab-quvvatlaydi.{:.0f}juftga yaxlitlaydi - bu IEEE 754 qoidasi.
Keyingi bo'limda ko'p oqimlilik bilan tanishamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.