# Soal 1: Estimasi E[X^2] dengan X ~ U(0,1)
set.seed(1)

# Buat 10.000 angka random dari distribusi Uniform(0,1)
x <- runif(10000, min = 0, max = 1)

# Hitung nilai E[X^2] dengan cara mengkuadratkan lalu ambil rata-rata
x_squared <- x^2
E_X2 <- mean(x_squared)

# Tampilkan hasil
cat("Estimasi E[X^2] =", round(E_X2, 4))
## Estimasi E[X^2] = 0.3349

Soal 1: Estimasi E[X²] untuk X ~ U(0,1)

set.seed(123)
x2 <- runif(10000)
E_X3_hat <- mean(x2^3)
cat("Estimasi E[X³] =", round(E_X3_hat, 4), "\n")
## Estimasi E[X³] = 0.246

Distribusi Uniform menghasilkan nilai acak yang tersebar merata dalam rentang tertentu. Grafik histogram menunjukkan bentuk persebaran yang hampir datar karena semua nilai memiliki peluang yang sama.

Soal 2: Simulasi dari N(100, 15²) dan analisis deskriptif

set.seed(2)
n1 <- rnorm(100, mean = 100, sd = 15)
n2 <- rnorm(1000, mean = 100, sd = 15)
n3 <- rnorm(10000, mean = 100, sd = 15)

par(mfrow=c(1,3))
hist(n1, main="n=100", col="lightblue")
hist(n2, main="n=1000", col="lightgreen")
hist(n3, main="n=10000", col="lightcoral")

Rataan dan simpangan baku dari data acak uniform mendekati nilai teoritis. Nilai rata-rata berada di tengah rentang, dan simpangan baku menunjukkan variasi data tetap.

cat("n1: Mean =", mean(n1), "SD =", sd(n1), "\n")
## n1: Mean = 99.53953 SD = 17.40284
cat("n2: Mean =", mean(n2), "SD =", sd(n2), "\n")
## n2: Mean = 101.0535 SD = 14.89456
cat("n3: Mean =", mean(n3), "SD =", sd(n3), "\n")
## n3: Mean = 100.0745 SD = 15.02745

Soal 3: Distribusi Binomial (30, 0.25), 5000 kali

set.seed(3)
binom_data <- rbinom(5000, size = 30, prob = 0.25)
hist(binom_data, main="Distribusi Binomial (30, 0.25)", col="orange")

mean(binom_data)
## [1] 7.5244

Semakin besar jumlah data (n), histogram distribusi uniform semakin halus dan menyerupai bentuk distribusi teoritis. Hal ini mendukung hukum bilangan besar.

Soal 4: Fungsi untuk menghitung s

hitung_s <- function(x) {
  n <- length(x)
  s <- sqrt((sum(x^2) - (sum(x)^2)/n) / (n - 1))
  return(s)
}

# Simulasi data N(89, 10), n = 1000
set.seed(4)
x_norm <- rnorm(1000, mean = 89, sd = 10)
s_hasil <- hitung_s(x_norm)
cat("Nilai s =", round(s_hasil, 4))
## Nilai s = 9.693

Distribusi uniform tetap merata meskipun intervalnya berbeda. Hanya posisi dan lebar sebarannya yang berubah sesuai dengan batas bawah dan atasnya.

Soal 5 – Simulasi Antrian di Bank

(a) Simulasi antrian selama 20 hari kerja

set.seed(123)

# Parameter simulasi
jumlah_hari <- 20
jam_per_hari <- 6
waktu_total <- jumlah_hari * jam_per_hari * 60  # dalam menit
lambda <- 5 / 60   # rata-rata 5 nasabah per jam (Poisson per menit)
mu <- 1 / 8        # pelayanan rata-rata 8 menit (Eksponensial)

# Simulasi kedatangan nasabah
waktu_kedatangan <- cumsum(rexp(ceiling(waktu_total * lambda * 1.5), rate = lambda))
waktu_kedatangan <- waktu_kedatangan[waktu_kedatangan <= waktu_total]
jumlah_nasabah <- length(waktu_kedatangan)

# Simulasi pelayanan dengan 2 teller
mulai_pelayanan <- numeric(jumlah_nasabah)
selesai_pelayanan <- numeric(jumlah_nasabah)
teller_selesai <- c(0, 0)  # waktu selesai masing-masing teller

for (i in 1:jumlah_nasabah) {
  waktu_pelayanan <- rexp(1, rate = mu)
  teller_dipakai <- which.min(teller_selesai)
  mulai <- max(waktu_kedatangan[i], teller_selesai[teller_dipakai])
  selesai <- mulai + waktu_pelayanan

  mulai_pelayanan[i] <- mulai
  selesai_pelayanan[i] <- selesai
  teller_selesai[teller_dipakai] <- selesai
}

(b) Hitung rata-rata waktu tunggu nasabah

waktu_tunggu <- mulai_pelayanan - waktu_kedatangan
cat("Rata-rata waktu tunggu nasabah:", round(mean(waktu_tunggu), 2), "menit\n")
## Rata-rata waktu tunggu nasabah: 0.85 menit

(c) Hitung persen waktu teller sibuk

total_waktu_kerja_teller <- 2 * waktu_total
total_waktu_pelayanan <- sum(selesai_pelayanan - mulai_pelayanan)
utilisasi <- total_waktu_pelayanan / total_waktu_kerja_teller

cat("Persentase teller sibuk:", round(utilisasi * 100, 2), "%\n")
## Persentase teller sibuk: 34.19 %

(d) Bandingkan jika teller jadi 3 orang

# Reset simulasi dengan 1 teller
teller1_selesai <- 0
mulai1 <- numeric(jumlah_nasabah)
selesai1 <- numeric(jumlah_nasabah)

for (i in 1:jumlah_nasabah) {
  waktu_pelayanan <- rexp(1, rate = mu)
  mulai <- max(waktu_kedatangan[i], teller1_selesai)
  selesai <- mulai + waktu_pelayanan

  mulai1[i] <- mulai
  selesai1[i] <- selesai
  teller1_selesai <- selesai
}

waktu_tunggu1 <- mulai1 - waktu_kedatangan
util1 <- sum(selesai1 - mulai1) / waktu_total

cat("Rata-rata waktu tunggu (1 teller):", round(mean(waktu_tunggu1), 2), "menit\n")
## Rata-rata waktu tunggu (1 teller): 10.17 menit
cat("Utilisasi 1 teller:", round(util1 * 100, 2), "%\n")
## Utilisasi 1 teller: 65.54 %

(e) Grafik panjang antrian sepanjang hari

library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.4.3
# Buat data panjang antrian berdasarkan event time
event_time <- sort(unique(c(waktu_kedatangan, selesai_pelayanan)))
queue_length <- sapply(event_time, function(t) {
  sum(waktu_kedatangan <= t & mulai_pelayanan > t)
})

# Plot
qplot(event_time, queue_length, geom = "line", xlab = "Waktu (menit)", ylab = "Jumlah dalam Antrian") +
  ggtitle("Panjang Antrian Sepanjang Waktu") +
  theme_minimal()
## Warning: `qplot()` was deprecated in ggplot2 3.4.0.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Menggunakan 2 teller jauh lebih efisien untuk menangani rata-rata 5 nasabah per jam. Sistem dengan 2 teller:

Mengurangi waktu tunggu nasabah

Menjaga antrian tetap pendek

Menyeimbangkan beban kerja

Memberikan pengalaman pelayanan yang lebih baik

Jika bank ingin tetap memberikan pelayanan cepat dan efisien, 2 teller adalah konfigurasi yang optimal.

Soal 6: Simulasi Toko Kelontong Bu Sari

(a) Simulasi Stok Beras Selama 60 Hari

set.seed(123)

stok_awal <- 100
hari_total <- 60
frekuensi_pesan <- 5
jumlah_pesan <- 50
penjualan_min <- 8
penjualan_max <- 15

stok <- stok_awal
stok_harian <- numeric(hari_total)
kehabisan_stok <- 0
total_kerugian <- 0

for (hari in 1:hari_total) {
  penjualan <- sample(penjualan_min:penjualan_max, 1)
  if (stok < penjualan) {
    kehabisan_stok <- kehabisan_stok + 1
    total_kerugian <- total_kerugian + (penjualan - stok) * 50000
    stok <- 0
  } else {
    stok <- stok - penjualan
  }

  if (hari %% frekuensi_pesan == 0) {
    stok <- stok + jumlah_pesan
  }

  stok_harian[hari] <- stok
}

stok_harian
##  [1] 86 72 62 49 89 80 71 58 48 86 75 62 49 41 82 72 57 45 35 75 67 56 48 40 78
## [26] 68 53 44 30 71 63 50 40 29 66 58 48 34 22 61 47 32 23 11 50 42 34 25 11 51
## [51] 40 28 14  2 50 35 22 14  5 50

(b) Jumlah Hari Kehabisan Stok dan Kerugian

cat("Jumlah hari kehabisan stok:", kehabisan_stok, "hari\n")
## Jumlah hari kehabisan stok: 3 hari
cat("Total kerugian akibat kehabisan stok: Rp", format(total_kerugian, big.mark = "."), "\n")
## Warning in prettyNum(.Internal(format(x, trim, digits, nsmall, width, 3L, :
## 'big.mark' and 'decimal.mark' are both '.', which could be confusing
## Total kerugian akibat kehabisan stok: Rp 9e+05

(c) Coba Berbagai Strategi Jumlah Pesan

strategi_jumlah_pesan <- c(40, 50, 60)
hasil_strategi <- data.frame(JumlahPesan = strategi_jumlah_pesan, Kehabisan = 0, Kerugian = 0)

for (i in 1:length(strategi_jumlah_pesan)) {
  stok <- stok_awal
  kehabisan <- 0
  rugi <- 0
  for (hari in 1:hari_total) {
    penjualan <- sample(penjualan_min:penjualan_max, 1)
    if (stok < penjualan) {
      kehabisan <- kehabisan + 1
      rugi <- rugi + (penjualan - stok) * 50000
      stok <- 0
    } else {
      stok <- stok - penjualan
    }
    if (hari %% frekuensi_pesan == 0) {
      stok <- stok + strategi_jumlah_pesan[i]
    }
  }
  hasil_strategi$Kehabisan[i] <- kehabisan
  hasil_strategi$Kerugian[i] <- rugi
}

hasil_strategi
##   JumlahPesan Kehabisan Kerugian
## 1          40        17  8350000
## 2          50         9  3950000
## 3          60         0        0

(d) Coba Ubah Frekuensi Pemesanan

frekuensi_opsi <- c(3, 5, 7)
hasil_frekuensi <- data.frame(Frekuensi = frekuensi_opsi, Kehabisan = 0, Kerugian = 0)

for (i in 1:length(frekuensi_opsi)) {
  stok <- stok_awal
  kehabisan <- 0
  rugi <- 0
  for (hari in 1:hari_total) {
    penjualan <- sample(penjualan_min:penjualan_max, 1)
    if (stok < penjualan) {
      kehabisan <- kehabisan + 1
      rugi <- rugi + (penjualan - stok) * 50000
      stok <- 0
    } else {
      stok <- stok - penjualan
    }
    if (hari %% frekuensi_opsi[i] == 0) {
      stok <- stok + jumlah_pesan
    }
  }
  hasil_frekuensi$Kehabisan[i] <- kehabisan
  hasil_frekuensi$Kerugian[i] <- rugi
}

hasil_frekuensi
##   Frekuensi Kehabisan Kerugian
## 1         3         0        0
## 2         5         2   700000
## 3         7        17  8700000

(e) Grafik Pergerakan Stok

plot(1:hari_total, stok_harian, type = "o", col = "blue", lwd = 2,
     xlab = "Hari", ylab = "Stok Beras", main = "Grafik Stok Beras Selama 60 Hari")
grid()

set.seed(123)

# Parameter simulasi
jumlah_hari <- 20
jam_per_hari <- 6
waktu_total <- jumlah_hari * jam_per_hari * 60  # dalam menit
lambda <- 5 / 60   # rata-rata 5 nasabah per jam (Poisson per menit)
mu <- 1 / 8        # pelayanan rata-rata 8 menit (Eksponensial)

# Simulasi kedatangan nasabah
waktu_kedatangan <- cumsum(rexp(ceiling(waktu_total * lambda * 1.5), rate = lambda))
waktu_kedatangan <- waktu_kedatangan[waktu_kedatangan <= waktu_total]
jumlah_nasabah <- length(waktu_kedatangan)

# Simulasi pelayanan dengan 2 teller
mulai_pelayanan <- numeric(jumlah_nasabah)
selesai_pelayanan <- numeric(jumlah_nasabah)
teller_selesai <- c(0, 0)  # waktu selesai masing-masing teller

for (i in 1:jumlah_nasabah) {
  waktu_pelayanan <- rexp(1, rate = mu)
  teller_dipakai <- which.min(teller_selesai)
  mulai <- max(waktu_kedatangan[i], teller_selesai[teller_dipakai])
  selesai <- mulai + waktu_pelayanan

  mulai_pelayanan[i] <- mulai
  selesai_pelayanan[i] <- selesai
  teller_selesai[teller_dipakai] <- selesai
}
waktu_tunggu <- mulai_pelayanan - waktu_kedatangan
cat("Rata-rata waktu tunggu nasabah:", round(mean(waktu_tunggu), 2), "menit\n")
## Rata-rata waktu tunggu nasabah: 0.85 menit
total_waktu_kerja_teller <- 2 * waktu_total
total_waktu_pelayanan <- sum(selesai_pelayanan - mulai_pelayanan)
utilisasi <- total_waktu_pelayanan / total_waktu_kerja_teller

cat("Persentase teller sibuk:", round(utilisasi * 100, 2), "%\n")
## Persentase teller sibuk: 34.19 %

Untuk menjaga keberlanjutan bisnis dan kepuasan pelanggan, Bu Sari perlu mengoptimalkan jumlah dan frekuensi pemesanan agar stok tetap tersedia dan kerugian akibat kekosongan barang dapat ditekan seminimal mungkin.