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:

  1. Hook (berkas ini): fungsi kecil yang dipanggil model saat sesuatu terjadi, untuk mencatat satu angka ke SIMLIB.
  2. 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)
Untukangka yang muncul satu per satu per kejadiannilai yang selalu ada dan berubah-ubah (jumlah orang di bus saat ini)
Contohdelay seorang penumpangjumlah orang di bus
Kapan dipanggiltiap kali kejadian selesaitiap kali nilai itu berubah, dengan nilai barunya
Rata-ratabiasa: jumlah ÷ banyaknyamemperhitungkan 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);
}
SintaksArti
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));
}
SintaksArti
int locationlokasi tempat orang itu menunggu (1, 2, atau 3)
double delaylama 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);
}
SintaksArti
int passengers_on_busjumlah orang di bus setelah perubahan
(double) passengers_on_buscast: 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));
}
SintaksArti
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);
}
SintaksArti
SAMPST_LOOP_TIMEkonstanta 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));
}
SintaksArti
int originlokasi 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

StatistikFungsiPencatatLaciDipanggil saat
(b) delay antrianstats_queue_delaysampst1-3orang diambil dari antrian
(c) jumlah di busstats_bus_count_changedtimest1jumlah di bus berubah
(d) lama berhentistats_bus_stopsampst4-6bus berangkat dari sebuah lokasi
(e) lama putaranstats_bus_loopsampst7bus berangkat dari rental
(f) lama di sistemstats_time_in_systemsampst8-10orang selesai turun
(a) jumlah di antriantidak ada hookfilest (otomatis)list 1-3SIMLIB melacak sendiri
(c) awalstats_inittimest1awal 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).