6. Statistik, bagian 1: stats_init dan lima hook
Kalau kata “level”, “laci”, “hook”, atau “dibobot” belum jelas, baca dulu
6A_Statistik_dari_Nol.md. Berkas itu menjelaskan semuanya dengan angka kecil.
Soal meminta enam kelompok statistik (a) sampai (f). Cara mengumpulkannya dibagi dua:
- Hook (berkas ini): fungsi kecil yang dipanggil model saat sesuatu terjadi, untuk mencatat satu angka ke SIMLIB.
- Laporan (berkas 7): di akhir simulasi, membaca kembali angka-angka itu lalu mencetaknya sebagai tabel.
Prinsip rancangan: statistik tidak mengubah keadaan model, hanya menerima angka. Karena itu model (berkas 3 dan 4) tidak tahu cara pencatatan, dan mengubah statistik tidak berisiko merusak logika bus.
Sebelum membaca kode, pahami dua fungsi pencatat SIMLIB.
6.1 Dua fungsi pencatat: sampst dan timest
Setiap statistik disimpan di sebuah “laci” bernomor. Nomor laci diberikan oleh makro di bagian atas file
(berkas 2): SAMPST_QUEUE_DELAY(loc), SAMPST_STOP_TIME(loc), dan seterusnya.
sampst(nilai, var) | timest(nilai, var) | |
|---|---|---|
| Untuk | angka yang muncul satu per satu per kejadian | nilai yang selalu ada dan berubah-ubah (jumlah orang di bus saat ini) |
| Contoh | delay seorang penumpang | jumlah orang di bus |
| Kapan dipanggil | tiap kali kejadian selesai | tiap kali nilai itu berubah, dengan nilai barunya |
| Rata-rata | biasa: jumlah ÷ banyaknya | memperhitungkan berapa lama tiap nilai berlaku |
Contoh perbedaannya, jumlah di bus selama 40 menit: 0 orang selama 10 menit, 5 orang selama 20 menit, 20 orang
selama 10 menit. Rata-rata terhadap waktu = (0×10 + 5×20 + 20×10) ÷ 40 = 7,5. Kalau dihitung seperti
sampst (rata-rata dari 0, 5, 20) hasilnya 8,3, keliru, karena nilai 20 hanya berlaku sebentar.
sampst(30.0, 1) dengan nomor positif berarti catat. sampst(0.0, -1) dengan nomor negatif berarti
minta laporan (itu dipakai di berkas 7).
6.2 stats_init
src/bus-sim.c baris 527-530
void stats_init(void)
{
timest(0.0, TIMEST_NUM_ON_BUS);
}| Sintaks | Arti |
|---|---|
void stats_init(void) | fungsi tanpa parameter dan tanpa nilai kembali |
timest(0.0, TIMEST_NUM_ON_BUS); | catat bahwa jumlah orang di bus saat ini bernilai 0 pada waktu sekarang (t = 0) |
Logika: memberi tahu SIMLIB bahwa bus mulai kosong pada t = 0. Dipanggil sekali oleh init_model.
Kenapa begini: rata-rata dan maksimum (c) sebenarnya tetap benar tanpa baris ini, karena SIMLIB sudah mengawali nilai 0. Yang akan salah adalah nilai minimum: ia akan terisi 1 (nilai pertama yang tercatat). Minimum (c) tidak dicetak, jadi ini terutama soal kerapian.
6.3 Hook (b): delay antrian
src/bus-sim.c baris 532-536
/* (b) delay in queue */
void stats_queue_delay(int location, double delay)
{
sampst(delay, SAMPST_QUEUE_DELAY(location));
}| Sintaks | Arti |
|---|---|
int location | lokasi tempat orang itu menunggu (1, 2, atau 3) |
double delay | lama menunggu orang itu (menit) |
SAMPST_QUEUE_DELAY(location) | makro: untuk lokasi 1, 2, 3 menjadi nomor laci 1, 2, 3 |
sampst(delay, ...) | masukkan angka delay ke laci itu |
Logika: setiap orang yang diambil dari antrian untuk naik mencatat delay-nya ke laci lokasinya. Laci 1 menampung delay semua orang di terminal 1, laci 2 terminal 2, laci 3 rental.
Kapan dipanggil: try_start_load (berkas 4.2), tepat setelah orang diambil dari antrian:
stats_queue_delay(bus.location, sim_time - bus.current.arrival_time). Jadi delay = waktu sekarang − waktu
tiba, dan berakhir saat orang diambil dari antrian, bukan saat selesai naik.
6.4 Hook (c): jumlah di bus
src/bus-sim.c baris 538-542
/* (c) number on the bus */
void stats_bus_count_changed(int passengers_on_bus)
{
timest((double) passengers_on_bus, TIMEST_NUM_ON_BUS);
}| Sintaks | Arti |
|---|---|
int passengers_on_bus | jumlah orang di bus setelah perubahan |
(double) passengers_on_bus | cast: timest meminta double, sedangkan jumlah orang bertipe int |
timest(..., TIMEST_NUM_ON_BUS) | jumlah orang di bus saat ini (laci 1) adalah sekian |
Logika: setiap kali jumlah di bus berubah, nilai baru dicatat. SIMLIB sendiri mengingat kapan panggilan terakhir dan mengalikan nilai lama dengan lama waktu yang telah berlalu.
Kapan dipanggil: dari bus_board (satu orang naik, jumlah bertambah) dan bus_alight (satu orang mulai
turun, jumlah berkurang), dengan bus_passenger_count() sebagai nilainya.
Kenapa timest, bukan sampst: yang dicatat adalah nilai yang selalu ada dan berubah-ubah (lihat berkas 6A).
6.5 Hook (d): lama bus berhenti
src/bus-sim.c baris 544-548
/* (d) time the bus is stopped */
void stats_bus_stop(int location, double stop_time)
{
sampst(stop_time, SAMPST_STOP_TIME(location));
}| Sintaks | Arti |
|---|---|
SAMPST_STOP_TIME(location) | makro: (NUM_LOCATIONS + (location)) = 3 + lokasi, jadi laci 4, 5, 6 untuk lokasi 1, 2, 3 |
Logika: setiap kali bus berangkat dari sebuah lokasi, lama ia berhenti di situ dicatat ke laci lokasi itu.
Kapan dipanggil: bus_depart: stats_bus_stop(here, sim_time - bus.arrival_time), yaitu waktu berangkat
dikurangi waktu tiba. Hanya pemberhentian yang sudah selesai yang dihitung.
6.6 Hook (e): lama satu putaran
src/bus-sim.c baris 550-554
/* (e) loop time */
void stats_bus_loop(double loop_time)
{
sampst(loop_time, SAMPST_LOOP_TIME);
}| Sintaks | Arti |
|---|---|
SAMPST_LOOP_TIME | konstanta 7, satu laci saja karena putaran tidak dibedakan menurut lokasi |
Logika: lama satu putaran dihitung dari keberangkatan dari rental mobil sampai keberangkatan berikutnya dari rental mobil.
Kapan dipanggil: bus_depart, hanya bila here == LOC_CAR_RENTAL:
stats_bus_loop(sim_time - bus.last_rental_departure), lalu bus.last_rental_departure = sim_time. Putaran
pertama dimulai dari keberangkatan di t = 0.
6.7 Hook (f): lama di sistem
src/bus-sim.c baris 556-560
/* (f) time in system by arrival location */
void stats_time_in_system(int origin, double time)
{
sampst(time, SAMPST_TIME_IN_SYSTEM(origin));
}| Sintaks | Arti |
|---|---|
int origin | lokasi asal orang itu (tempat ia mula-mula tiba) |
SAMPST_TIME_IN_SYSTEM(origin) | makro: (7 + (origin)), jadi laci 8, 9, 10 untuk asal 1, 2, 3 |
Logika: setiap orang yang selesai turun mencatat total waktunya di sistem, dikelompokkan menurut lokasi asal (sesuai permintaan soal: “by arrival location”).
Kapan dipanggil: event_end_unload: stats_time_in_system(bus.current.origin, sim_time - bus.current.arrival_time). Jadi lama di sistem berakhir saat orang selesai turun.
6.8 Ringkasan lima hook dan satu fungsi awal
| Statistik | Fungsi | Pencatat | Laci | Dipanggil saat |
|---|---|---|---|---|
| (b) delay antrian | stats_queue_delay | sampst | 1-3 | orang diambil dari antrian |
| (c) jumlah di bus | stats_bus_count_changed | timest | 1 | jumlah di bus berubah |
| (d) lama berhenti | stats_bus_stop | sampst | 4-6 | bus berangkat dari sebuah lokasi |
| (e) lama putaran | stats_bus_loop | sampst | 7 | bus berangkat dari rental |
| (f) lama di sistem | stats_time_in_system | sampst | 8-10 | orang selesai turun |
| (a) jumlah di antrian | tidak ada hook | filest (otomatis) | list 1-3 | SIMLIB melacak sendiri |
| (c) awal | stats_init | timest | 1 | awal simulasi |
Catatan: laci sampst dan laci timest adalah dua kelompok nomor yang terpisah, jadi laci timest nomor 1
tidak bertabrakan dengan laci sampst nomor 1.
Kenapa (a) tanpa hook: panjang antrian adalah panjang sebuah list SIMLIB, dan SIMLIB sudah mencatatnya
otomatis setiap list_file atau list_remove (lewat filest, dijelaskan di berkas 7).