7. Statistik, bagian 2: laporan (stats_report_line, stats_report_sampst, stats_report)
Di akhir simulasi (menit 4800), main memanggil report, yang memanggil stats_report. Tugasnya: membaca
angka yang sudah dikumpulkan hook, lalu mencetaknya sebagai satu tabel.
Tiga fungsi bekerja berlapis:
stats_report (mencetak seluruh tabel (a)-(f))
├─ stats_report_sampst (siapkan satu baris dari laci sampst)
│ └─ stats_report_line (cetak satu baris)
└─ stats_report_line (cetak satu baris, untuk (a) dan (c))
Kita bahas dari lapisan paling bawah.
7.1 stats_report_line: mencetak satu baris tabel
src/bus-sim.c baris 562-573
void stats_report_line(FILE *out, const char *label, double avg, double max,
double min, int max_is_count)
{
char avg_text[32], max_text[32], min_text[32];
if (avg < 0.0) sprintf(avg_text, "-"); else sprintf(avg_text, "%.3f", avg);
if (max < 0.0) sprintf(max_text, "-");
else sprintf(max_text, max_is_count ? "%.0f" : "%.3f", max);
if (min < 0.0) sprintf(min_text, "-"); else sprintf(min_text, "%.3f", min);
fprintf(out, "%-42s | %9s | %9s | %9s\n", label, avg_text, max_text, min_text);
}Baris demi baris
| Baris kode | Sintaks | Logika |
|---|---|---|
void stats_report_line(FILE *out, const char *label, double avg, double max, double min, int max_is_count) | enam parameter | menerima tujuan cetak, nama baris, tiga angka (rata-rata, maks, min), dan penanda |
char avg_text[32], max_text[32], min_text[32]; | tiga larik karakter masing-masing 32 | tempat menyusun teks tiap sel tabel |
if (avg < 0.0) sprintf(avg_text, "-"); else sprintf(avg_text, "%.3f", avg); | if ... else, tanpa kurung kurawal | bila avg negatif, sel diisi -; selain itu diisi angka tiga desimal |
if (max < 0.0) sprintf(max_text, "-"); | bila max negatif, sel diisi - | |
else sprintf(max_text, max_is_count ? "%.0f" : "%.3f", max); | operator ? : memilih teks format | selain itu: bila max_is_count benar pakai %.0f (bilangan bulat), bila tidak %.3f |
if (min < 0.0) sprintf(min_text, "-"); else sprintf(min_text, "%.3f", min); | seperti avg | |
fprintf(out, "%-42s | %9s | %9s | %9s\n", label, avg_text, max_text, min_text); | cetak satu baris | label rata kiri 42 lebar, lalu tiga sel rata kanan 9 lebar, dipisah | |
Kenapa nilai negatif berarti ”-”
Semua angka di tabel ini (waktu, jumlah orang) tidak pernah negatif. Jadi nilai -1.0 aman dipakai sebagai
tanda “tidak ada nilai”. Pemanggil cukup mengirim -1.0, dan fungsi ini yang mengubahnya menjadi -.
Dengan begitu satu fungsi melayani semua baris, baik yang punya min (d, e, f) maupun yang tidak (a, b, c).
Kenapa max_is_count
Maksimum antrian dan jumlah di bus adalah jumlah orang, jadi lebih baik tampil 27 daripada 27.000.
Parameter max_is_count = 1 memilih format %.0f untuk itu; 0 memakai %.3f untuk waktu.
Kenapa lewat sprintf dulu, baru fprintf
sprintf menyusun teks setiap sel dulu ke larik (avg_text dan kawan-kawan) sehingga bisa memilih antara
- dan angka. Baru kemudian fprintf mencetak keempat teks itu sekaligus dengan lebar kolom yang rata. Kalau
langsung mencetak angka, tidak bisa menyisipkan -.
Contoh jalan (menelusuri kode dengan angka contoh)
| Pemanggilan | Hasil baris |
|---|---|
stats_report_line(out, "[b] Delay ...", 31.414, 91.934, -1.0, 0) | [b] Delay ... | 31.414 | 91.934 | - |
stats_report_line(out, "[a] Number ...", 7.368, 27.0, -1.0, 1) | [a] Number ... | 7.368 | 27 | - |
stats_report_line(out, label, -1.0, -1.0, -1.0, 0) | ketiga sel - (dipakai bila belum ada data) |
7.2 stats_report_sampst: menyiapkan satu baris dari laci sampst
src/bus-sim.c baris 575-590
/* A row from a sampst variable; show_min = 0 prints "-" for the minimum. */
void stats_report_sampst(FILE *out, const char *label, int variable, int show_min)
{
double count, avg, max, min;
sampst(0.0, -variable);
avg = transfer[1];
count = transfer[2];
max = transfer[3];
min = transfer[4];
if (count == 0.0)
stats_report_line(out, label, -1.0, -1.0, -1.0, 0);
else
stats_report_line(out, label, avg, max, show_min ? min : -1.0, 0);
}Baris demi baris
| Baris kode | Sintaks | Logika |
|---|---|---|
void stats_report_sampst(FILE *out, const char *label, int variable, int show_min) | parameter variable = nomor laci; show_min = 0 atau 1 | menerima nomor laci mana yang akan dibaca dan apakah minimum ditampilkan |
double count, avg, max, min; | empat variabel double dalam satu deklarasi | tempat menyalin hasil laporan; harus di awal fungsi (aturan C89) |
sampst(0.0, -variable); | tanda minus di depan variable | minta laporan laci itu; angka pertama (0.0) diabaikan |
avg = transfer[1]; | transfer larik milik SIMLIB | ambil rata-rata |
count = transfer[2]; | ambil jumlah observasi | |
max = transfer[3]; | ambil maksimum | |
min = transfer[4]; | ambil minimum | |
if (count == 0.0) | == membandingkan | bila belum ada observasi |
stats_report_line(out, label, -1.0, -1.0, -1.0, 0); | tiga -1.0 | cetak baris berisi tanda - saja |
else … stats_report_line(out, label, avg, max, show_min ? min : -1.0, 0); | show_min ? min : -1.0 | selain itu cetak angkanya; bila show_min benar kolom Min diisi min, bila salah diisi -1.0 (jadi -) |
Hal penting
transfer[]harus disalin segera. Setiap panggilan SIMLIB berikutnya menimpanya. Karena itu empat angka langsung dipindah ke variabel lokal sebelum memanggilstats_report_line.- Urutan isi hasil
sampst:[1]rata-rata,[2]jumlah,[3]maksimum,[4]minimum. Indeks tertukar menghasilkan angka salah tanpa pesan error apa pun. - Kenapa ada pengecekan
count == 0.0: kalau laci kosong, SIMLIB mengisi maks dan min dengan angka sentinel1e30(sangat besar) yang tidak boleh dicetak apa adanya. Jadi baris dicetak dengan-. - Kenapa
show_min: soal hanya meminta rata-rata dan maksimum untuk delay (b), jadi kolom Min diberi-(show_min = 0). Untuk (d), (e), (f) soal meminta ketiganya, jadishow_min = 1.
7.3 stats_report: mencetak seluruh tabel
src/bus-sim.c baris 592-634
/* Prints (a)-(f) as one table. */
void stats_report(FILE *out)
{
int loc;
char label[64];
double avg, max;
fprintf(out, "Locations: 1 = %s, 2 = %s, 3 = %s\n",
locations[1].name, locations[2].name, locations[3].name);
fprintf(out, "All times are in minutes\n\n");
fprintf(out, "%-42s | %9s | %9s | %9s\n", "", "Average", "Max", "Min");
for (loc = 1; loc <= NUM_LOCATIONS; ++loc) {
sprintf(label, "%sNumber in queue at location %d", loc == 1 ? "[a] " : " ", loc);
filest(LIST_QUEUE(loc));
avg = transfer[1];
max = transfer[2];
stats_report_line(out, label, avg, max, -1.0, 1);
}
for (loc = 1; loc <= NUM_LOCATIONS; ++loc) {
sprintf(label, "%sDelay in queue at location %d", loc == 1 ? "[b] " : " ", loc);
stats_report_sampst(out, label, SAMPST_QUEUE_DELAY(loc), 0);
}
timest(0.0, -TIMEST_NUM_ON_BUS);
avg = transfer[1];
max = transfer[2];
stats_report_line(out, "[c] Number on the bus", avg, max, -1.0, 1);
for (loc = 1; loc <= NUM_LOCATIONS; ++loc) {
sprintf(label, "%sBus stop time at location %d", loc == 1 ? "[d] " : " ", loc);
stats_report_sampst(out, label, SAMPST_STOP_TIME(loc), 1);
}
stats_report_sampst(out, "[e] Bus loop time", SAMPST_LOOP_TIME, 1);
for (loc = 1; loc <= NUM_LOCATIONS; ++loc) {
sprintf(label, "%sTime in system, arrived at location %d",
loc == 1 ? "[f] " : " ", loc);
stats_report_sampst(out, label, SAMPST_TIME_IN_SYSTEM(loc), 1);
}
}Kepala tabel
| Baris kode | Logika |
|---|---|
int loc; char label[64]; double avg, max; | penghitung lokasi, tempat menyusun nama baris, dan tempat menyalin hasil |
fprintf(out, "Locations: 1 = %s, 2 = %s, 3 = %s\n", locations[1].name, ...) | cetak daftar lokasi; tiap %s diisi satu nama dari tabel locations |
fprintf(out, "All times are in minutes\n\n"); | keterangan satuan; \n\n menyisakan satu baris kosong |
fprintf(out, "%-42s | %9s | %9s | %9s\n", "", "Average", "Max", "Min"); | judul kolom; sel pertama teks kosong selebar 42 agar sejajar dengan label baris |
Pola yang berulang: menyusun nama baris
sprintf(label, "%sNumber in queue at location %d", loc == 1 ? "[a] " : " ", loc);| Bagian | Arti |
|---|---|
%s pertama | diisi hasil loc == 1 ? "[a] " : " ": tanda [a] bila loc 1, empat spasi bila bukan |
Number in queue at location | teks tetap |
%d | diisi loc (1, 2, atau 3) |
Hasilnya [a] Number in queue at location 1, lalu Number in queue at location 2 (diawali empat
spasi), dan seterusnya. Tanda [a] hanya di baris pertama kelompoknya.
Statistik (a): jumlah di antrian
| Kode | Logika |
|---|---|
for (loc = 1; loc <= NUM_LOCATIONS; ++loc) { ... } | ulangi untuk lokasi 1, 2, 3 |
filest(LIST_QUEUE(loc)); | minta SIMLIB melaporkan panjang list antrian lokasi itu dari waktu ke waktu |
avg = transfer[1]; max = transfer[2]; | rata-rata terhadap waktu dan maksimum (urutan isi filest: [1] rata-rata, [2] maks, [3] min) |
stats_report_line(out, label, avg, max, -1.0, 1); | cetak; -1.0 = kolom Min tidak diminta, 1 = maksimum dicetak sebagai bilangan bulat |
Statistik (b): delay antrian
stats_report_sampst(out, label, SAMPST_QUEUE_DELAY(loc), 0);Satu baris per lokasi dari laci sampst nomor loc. Angka 0 di ujung berarti kolom Min tidak dicetak.
Statistik (c): jumlah di bus
| Kode | Logika |
|---|---|
timest(0.0, -TIMEST_NUM_ON_BUS); | minta laporan laci timest (tanda minus) |
avg = transfer[1]; max = transfer[2]; | urutan isi timest: [1] rata-rata terhadap waktu, [2] maks, [3] min |
stats_report_line(out, "[c] Number on the bus", avg, max, -1.0, 1); | satu baris; maks sebagai bilangan bulat |
Hanya satu baris karena hanya ada satu bus.
Statistik (d), (e), (f)
stats_report_sampst(out, label, SAMPST_STOP_TIME(loc), 1);
stats_report_sampst(out, "[e] Bus loop time", SAMPST_LOOP_TIME, 1);
stats_report_sampst(out, label, SAMPST_TIME_IN_SYSTEM(loc), 1);Polanya sama dengan (b); bedanya angka 1 (kolom Min ikut dicetak) dan nomor laci. (d) satu baris per
lokasi, (e) satu baris untuk putaran, (f) satu baris per lokasi asal.
Dua urutan isi hasil yang berbeda
| Fungsi pembaca | transfer[1] | transfer[2] | transfer[3] | transfer[4] |
|---|---|---|---|---|
sampst(0.0, -var) | rata-rata | jumlah | maks | min |
timest(0.0, -var) dan filest(list) | rata-rata terhadap waktu | maks | min | (tidak ada) |
Itu sebabnya stats_report_sampst membaca [2] sebagai jumlah dan [3] sebagai maks, sedangkan
bagian (a) dan (c) di stats_report membaca [2] sebagai maks.
Kenapa stats_report aman dipanggil dua kali
main memanggil report dua kali (layar dan berkas). Meminta laporan tidak mengubah angka, jadi kedua hasil
identik.