SPM KMK 2216 study materials
SPM KMK 2216 study resources

Diskaun koperasi yang tersasar RM0.47

SPM KMK 2216 · Put your knowledge to work in context.

All case studies

Diskaun koperasi yang tersasar RM0.47

Kedai buku koperasi SMK Seri Pagi menjual buku kerja pada harga RM12.90. Ahli kelab koperasi mendapat diskaun 15%, dan setiap pesanan melalui pos dikenakan caj RM3.50. Koperasi menerima kira-kira 60 pesanan sehari. Seorang pelajar menulis atur cara ini:

int harga = 12.90;
int diskaun = harga * 15 / 100;
double jumlah = harga - diskaun + 3.50;

Apabila pelajar itu menguji pesanan seorang ahli, atur cara memaparkan RM14.50, bukan RM14.47. Selepas dia menukar int harga kepada double harga, jumlah yang dipaparkan menjadi 14.465, tetapi semakan if (jumlah == 14.47) masih gagal. Guru juga mendapati seorang ahli yang membeli tiga buku dalam satu pesanan tidak menerima diskaun sama sekali kerana 15 / 100 dikira sebagai integer, dan baki kad seorang ahli yang sepatutnya RM0.00 dipaparkan sebagai RM0.0000000001. Koperasi akan menggunakan atur cara ini untuk jualan minggu hadapan, jadi pembetulan mesti dibuat pada jenis data, operator dan perbandingan sebelum program diserahkan.

1. Terangkan mengapa atur cara memaparkan RM14.50. Nyatakan dua punca berasingan dan tunjukkan pembetulan yang menghasilkan RM14.47.

Read the worked answer

Punca pertama - penukaran jenis data secara tersirat. Literal 12.90 ialah nilai floating-point. Apabila ia dimasukkan ke dalam int harga, nilainya dipotong (truncate), bukan dibundarkan: harga menjadi 12, jadi RM0.90 hilang sebelum sebarang pengiraan berlaku.

Punca kedua - pembahagian integer. Dalam harga * 15 / 100, ketiga-tiga operand ialah int. 12 * 15 = 180, kemudian 180 / 100 = 1 (baki 80 dibuang). Diskaun sebenar sepatutnya 12.90 × 0.15 = RM1.935, tetapi atur cara menolak RM1 sahaja.

Kiraan yang terhasil: 12 − 1 + 3.50 = RM14.50.

Pembetulan:

double harga = 12.90;
double diskaun = harga * 15 / 100.0;    // satu operand double -> seluruh ungkapan jadi double
double jumlah = harga - diskaun + 3.50; // 14.465

atau diskaun = harga * 0.15. Bundarkan hanya semasa memaparkan: printf('%.2f', jumlah) atau Math.round(jumlah * 100) / 100.0 → 14.47. Jika diskaun dibundarkan awal (kepada RM1.94), ralat akan terkumpul apabila satu pesanan mengandungi banyak buku, jadi bundarkan sekali di hujung sahaja.

2. Mengapa `if (jumlah == 14.47)` masih gagal selepas jenis data ditukar kepada `double`? Cadangkan perbandingan yang lebih sesuai.

Read the worked answer

14.47 dan 14.465 tidak mempunyai perwakilan binari yang tepat dalam double. Nilai 12.90, 1.935 dan 3.50 masing-masing disimpan sebagai penghampiran terdekat, dan hasil tambahnya mungkin tersimpan sebagai 14.464999999999999 atau 14.465000000000002, manakala literal 14.47 tersimpan sebagai 14.470000000000001. Operator == membandingkan corak bit yang tersimpan, bukan nilai matematik, jadi perbandingan gagal walaupun secara logik jumlahnya sama.

Pembetulan yang lebih selamat: bandingkan dengan toleransi, contohnya if (Math.abs(jumlah - 14.47) < 0.005). Untuk wang, lebih baik simpan dalam sen sebagai integer: int hargaSen = 1290; int diskaunSen = 194; kemudian bandingkan jumlahSen == 1447 - perbandingan integer tepat dan tiada ralat terkumpul.

Jangan 'membetulkan' semakan dengan menukar literal kepada 14.465; itu hanya menyembunyikan masalah untuk satu kes dan akan gagal semula apabila harga atau bilangan buku berubah.

3. Koperasi bercadang menyimpan semua nilai wang sebagai integer sen (1290, 350). Bincangkan satu kelebihan dan satu kelemahan, dan nyatakan satu operasi dalam atur cara ini yang perlu diubah.

Read the worked answer

Kelebihan: semua nilai wang menjadi integer, jadi tiada ralat perwakilan binari, tiada masalah ==, dan tiada ralat terkumpul apabila 60 pesanan dijumlahkan setiap hari. Akauntan juga boleh mengaudit setiap sen tanpa pembundaran tersembunyi.

Kelemahan: setiap input dan output perlu ditukar (RM12.90 → 1290, dan 1447 → RM14.47). Diskaun 15% menghasilkan 193.5 sen, iaitu keputusan pembundaran yang mesti ditetapkan dasarnya (separuh ke atas, atau kepada sen terdekat) dan didokumenkan; jika pemaju terlupa membahagi dengan 100 semasa memaparkan, harga muncul 100 kali ganda.

Operasi yang perlu diubah: pengiraan diskaun menjadi diskaunSen = (hargaSen * 15 + 50) / 100 (pembundaran separuh ke atas), dan pemaparan menjadi printf('RM%.2f', jumlahSen / 100.0). Namakan pemboleh ubah dengan unit (hargaSen, jumlahSen) supaya salah unit mudah dikesan semasa semakan kod, dan tetapkan satu peraturan pembundaran untuk seluruh sistem.