Math #
Komputasi matematika adalah kebutuhan yang muncul di hampir semua domain pemrograman — dari kalkulasi harga diskon di e-commerce, pemrosesan sinyal audio, simulasi fisika game, hingga algoritma machine learning. Ruby menyediakan tiga lapis fasilitas matematika: modul Math untuk fungsi ilmiah (trigonometri, logaritma, akar), method bawaan pada kelas Numeric, Integer, dan Float untuk operasi sehari-hari, serta BigDecimal dan Rational untuk kebutuhan presisi tinggi. Memahami kapan menggunakan masing-masing lapisan ini — dan jebakan presisi floating-point yang mengintai — adalah kunci untuk menulis program yang menghasilkan angka yang benar.
Modul Math dan Konstanta #
Math adalah modul bawaan Ruby yang menyediakan fungsi matematika ilmiah. Tidak perlu require — tersedia langsung sejak Ruby dimuat.
# Konstanta bawaan
Math::PI # => 3.141592653589793 (π)
Math::E # => 2.718281828459045 (bilangan Euler)
# Menggunakan include untuk akses tanpa prefix
include Math
PI # => 3.141592653589793
sqrt(16) # => 4.0
Semua method Math mengembalikan Float, bahkan jika input adalah Integer. Ini penting dipahami karena mempengaruhi presisi hasil komputasi.
Math.sqrt(9) # => 3.0 (Float, bukan Integer!)
Math.sqrt(2) # => 1.4142135623730951
Math.sqrt(-1) # => NaN (tidak error, tapi Not a Number)
# Cek hasil tidak valid
hasil = Math.sqrt(-5)
hasil.nan? # => true
hasil.infinite? # => nil
# Konstanta Float khusus
Float::INFINITY # => Infinity
-Float::INFINITY # => -Infinity
Float::NAN # => NaN
| Konstanta / Method | Nilai | Keterangan |
|---|---|---|
Math::PI | 3.14159265358979… | π — rasio keliling terhadap diameter lingkaran |
Math::E | 2.71828182845904… | Bilangan Euler — basis logaritma natural |
Float::INFINITY | ∞ | Tak hingga positif |
Float::NAN | NaN | Not a Number — hasil operasi tidak terdefinisi |
Float::EPSILON | 2.22e-16 | Selisih terkecil antara dua Float berbeda |
Float::DIG | 15 | Jumlah digit desimal presisi Float |
Akar dan Pangkat #
Operasi akar dan pangkat adalah fondasi dari banyak algoritma. Ruby menyediakannya di beberapa tempat dengan trade-off yang berbeda.
# Akar kuadrat
Math.sqrt(25) # => 5.0
Math.sqrt(2) # => 1.4142135623730951
# Akar dengan pangkat (akar n)
# Tidak ada Math.cbrt di Ruby, gunakan rumus pangkat
Math.cbrt = lambda { |x| x < 0 ? -((-x) ** (1.0/3)) : x ** (1.0/3) }
# Atau langsung:
27 ** (1.0/3) # => 3.0 (akar kubik 27)
8 ** (1.0/3) # => 2.0
16 ** (1.0/4) # => 2.0 (akar pangkat 4)
# Pangkat dengan operator **
2 ** 10 # => 1024 (Integer result karena basis dan eksponen Integer)
2 ** 0.5 # => 1.4142135623730951 (Float jika eksponen Float)
2.0 ** 10 # => 1024.0 (Float jika basis Float)
# Integer.pow dengan modulo — efisien untuk kriptografi
# (a ** b) % m
2.pow(10, 1000) # => 24 (ekuivalen dengan (2**10) % 1000, tapi lebih efisien)
# Math.hypot — panjang hipotenusa, menghindari overflow
Math.hypot(3, 4) # => 5.0 (sqrt(3² + 4²))
Math.hypot(5, 12) # => 13.0
flowchart TD
A[Butuh akar / pangkat] --> B{Tipe hasil?}
B -- "Integer exact" --> C{Apakah hasilnya\npasti bilangan bulat?}
B -- "Float OK" --> D["x ** eksponen_float\natau Math.sqrt(x)"]
C -- Ya --> E["Integer ** Integer\ncontoh: 2 ** 8 => 256"]
C -- Tidak --> F["Konversi dulu:\nx.to_f ** (1.0/n)"]
D --> G{Perlu presisi\ntinggi?}
G -- Ya --> H["BigDecimal + sqrt"]
G -- Tidak --> D27 ** (1.0/3)seharusnya menghasilkan tepat3.0, tapi karena1.0/3adalah0.3333...dalam floating-point, hasilnya bisa2.9999999999999996di beberapa kasus tergantung platform. Jika presisi integer penting, verifikasi dengan pembulatan:(x ** (1.0/n)).round.
Fungsi Trigonometri #
Fungsi trigonometri di Math semuanya bekerja dengan radian, bukan derajat. Ini sumber kesalahan yang sangat umum bagi pemula maupun developer berpengalaman yang berpindah dari lingkungan yang default ke derajat.
# Fungsi dasar — semua argumen dalam RADIAN
Math.sin(0) # => 0.0
Math.sin(Math::PI / 2) # => 1.0 (sin 90°)
Math.cos(0) # => 1.0
Math.cos(Math::PI) # => -1.0 (cos 180°)
Math.tan(Math::PI / 4) # => 0.9999... (tan 45° ≈ 1.0)
# Fungsi invers (arc)
Math.asin(1.0) # => 1.5707963... (π/2 = 90°)
Math.acos(1.0) # => 0.0 (0°)
Math.atan(1.0) # => 0.7853... (π/4 = 45°)
Math.atan2(1, 1) # => 0.7853... (π/4)
Math.atan2(-1, -1) # => -2.3561... (225° atau -135°)
# Konversi derajat ↔ radian
def derajat_ke_radian(derajat)
derajat * Math::PI / 180.0
end
def radian_ke_derajat(radian)
radian * 180.0 / Math::PI
end
Math.sin(derajat_ke_radian(30)) # => 0.5 (sin 30°)
Math.cos(derajat_ke_radian(60)) # => 0.5 (cos 60°)
radian_ke_derajat(Math::PI) # => 180.0
radian_ke_derajat(Math::PI / 2) # => 90.0
# ANTI-PATTERN: langsung memasukkan derajat ke fungsi trigonometri
sudut = 45
Math.sin(sudut) # => 0.8509... SALAH! sin(45 radian), bukan sin(45°)
# BENAR: konversi dulu ke radian
Math.sin(sudut * Math::PI / 180) # => 0.7071... (sin 45° yang benar)
Math.atan2(y, x) patut mendapat perhatian khusus — ini adalah versi superior dari atan karena menangani semua kuadran dengan benar dan tidak pernah membagi dengan nol:
# atan2 mengembalikan sudut dalam range (-π, π]
Math.atan2(1, 0) # => π/2 (90°) — ke atas
Math.atan2(-1, 0) # => -π/2 (-90°) — ke bawah
Math.atan2(0, -1) # => π (180°) — ke kiri
Math.atan2(0, 1) # => 0 (0°) — ke kanan
# Aplikasi: hitung sudut antara dua titik
def sudut_antara(x1, y1, x2, y2)
radian_ke_derajat(Math.atan2(y2 - y1, x2 - x1))
end
sudut_antara(0, 0, 1, 1) # => 45.0°
sudut_antara(0, 0, 0, 1) # => 90.0°
Fungsi Hiperbolik #
Fungsi hiperbolik berguna dalam komputasi ilmiah, pemrosesan sinyal, dan jaringan saraf tiruan (fungsi aktivasi seperti tanh).
Math.sinh(0) # => 0.0 (sinus hiperbolik)
Math.cosh(0) # => 1.0 (cosinus hiperbolik)
Math.tanh(0) # => 0.0 (tangen hiperbolik)
Math.tanh(1) # => 0.7615941559557649
# Identitas: cosh²(x) - sinh²(x) = 1
x = 2.5
(Math.cosh(x) ** 2 - Math.sinh(x) ** 2).round(10) # => 1.0
# Invers hiperbolik
Math.asinh(0) # => 0.0
Math.acosh(1) # => 0.0
Math.atanh(0) # => 0.0
Logaritma dan Eksponensial #
Logaritma dan eksponensial adalah operasi inti dalam analisis kompleksitas algoritma, statistik, dan keuangan (bunga majemuk, pertumbuhan eksponensial).
# Eksponensial — e^x
Math.exp(0) # => 1.0
Math.exp(1) # => 2.718281828459045 (nilai e)
Math.exp(2) # => 7.38905609893065
# Logaritma natural (basis e)
Math.log(1) # => 0.0
Math.log(Math::E) # => 1.0
Math.log(Math::E**2) # => 2.0
# Logaritma dengan basis tertentu
Math.log(100, 10) # => 2.0 (log₁₀)
Math.log(8, 2) # => 3.0 (log₂)
Math.log(27, 3) # => 3.0 (log₃)
# Logaritma basis 2 dan 10 — shortcut
Math.log2(1024) # => 10.0
Math.log10(1000) # => 3.0
Math.log10(0.001) # => -3.0
# Aplikasi: hitung pertumbuhan eksponensial
# Formula: A = P * e^(r*t)
def pertumbuhan_kontinu(pokok, laju_tahunan, tahun)
pokok * Math.exp(laju_tahunan * tahun)
end
# Rp 10jt dengan laju 5% per tahun selama 10 tahun
hasil = pertumbuhan_kontinu(10_000_000, 0.05, 10)
puts "Hasil: Rp #{hasil.round.to_s.reverse.scan(/.{1,3}/).join('.').reverse}"
# Konversi antara basis logaritma
# log_b(x) = ln(x) / ln(b)
def log_basis(x, b)
Math.log(x) / Math.log(b)
end
log_basis(32, 2) # => 5.0 (2^5 = 32)
log_basis(243, 3) # => 5.0 (3^5 = 243)
flowchart LR
A[Operasi Logaritma] --> B{Basis?}
B -- "e (natural)" --> C["Math.log(x)"]
B -- "2" --> D["Math.log2(x)"]
B -- "10" --> E["Math.log10(x)"]
B -- "Lainnya b" --> F["Math.log(x, b)\natau\nMath.log(x)/Math.log(b)"]
C --> G[Float result]
D --> G
E --> G
F --> GMath.log(0)menghasilkan-Infinity, danMath.log(-1)menghasilkanNaN. Keduanya tidak melempar exception — program tetap berjalan dengan nilai yang tidak valid. Selalu validasi input sebelum memanggil fungsi logaritma jika ada kemungkinan nilai nol atau negatif.
Pembulatan dan Pemotongan #
Konversi Float ke Integer dengan berbagai strategi pembulatan adalah operasi yang sangat umum, terutama dalam kalkulasi keuangan dan tampilan data.
angka = 3.7
# round — bulatkan ke bilangan terdekat (default: 0 desimal)
angka.round # => 4
3.5.round # => 4 (Ruby: setengah dibulatkan ke atas jika positif)
(-3.5).round # => -4 (ke bawah untuk negatif — "round half away from zero")
3.567.round(2) # => 3.57 (2 desimal)
3.567.round(1) # => 3.6
1234.5.round(-2) # => 1200 (bulatkan ke ratusan terdekat)
# ceil — bulatkan ke atas (ke infinity)
3.1.ceil # => 4
-3.7.ceil # => -3 (ke atas menuju 0)
3.123.ceil(2) # => 3.13
# floor — bulatkan ke bawah (ke -infinity)
3.9.floor # => 3
-3.1.floor # => -4 (ke bawah menjauhi 0)
3.987.floor(2) # => 3.98
# truncate — potong desimal (ke arah 0)
3.9.truncate # => 3 (sama dengan floor untuk positif)
-3.9.truncate # => -3 (berbeda dengan floor untuk negatif!)
# divmod — bagi dan sisa sekaligus
17.divmod(5) # => [3, 2] ([hasil_bagi, sisa])
(-17).divmod(5) # => [-4, 3] (floor division)
Perbedaan antara truncate dan floor untuk bilangan negatif sering menjadi sumber bug:
# truncate — potong menuju nol
-3.9.truncate # => -3 (mendekati 0)
# floor — bulatkan ke bawah (ke -infinity)
-3.9.floor # => -4 (menjauhi 0)
# ANTI-PATTERN: asumsi truncate == floor
def halaman(offset, per_halaman)
(offset / per_halaman.to_f).truncate # salah untuk offset negatif
end
# BENAR: gunakan Integer division atau floor eksplisit
def halaman(offset, per_halaman)
offset / per_halaman # Integer division — floor secara default di Ruby
end
| Method | 3.7 | -3.7 | Prinsip |
|---|---|---|---|
round | 4 | -4 | Ke terdekat, setengah menjauhi nol |
ceil | 4 | -3 | Selalu ke atas (→ +∞) |
floor | 3 | -4 | Selalu ke bawah (→ -∞) |
truncate | 3 | -3 | Selalu ke arah nol |
Operasi Integer #
Kelas Integer Ruby menyimpan banyak method matematika yang berguna di luar sekadar operator aritmetika biasa.
# Nilai absolut
(-5).abs # => 5
(-3.7).abs # => 3.7
# GCD dan LCM — penting untuk fraksi dan algoritma
12.gcd(8) # => 4 (Greatest Common Divisor)
12.lcm(8) # => 24 (Least Common Multiple)
12.gcd(0) # => 12
12.gcdlcm(8) # => [4, 24] (keduanya sekaligus)
# Cek prima — tidak ada method bawaan di Ruby murni
# Perlu require 'prime'
require 'prime'
Prime.prime?(7) # => true
Prime.prime?(10) # => false
Prime.prime?(2) # => true
# Generate bilangan prima
Prime.first(10) # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Prime.each(20) { |p| print "#{p} " }
# => 2 3 5 7 11 13 17 19
# Faktorisasi prima
Prime.prime_division(12) # => [[2, 2], [3, 1]] (2² × 3¹)
Prime.prime_division(60) # => [[2, 2], [3, 1], [5, 1]]
# Digits — pecah integer menjadi array digit
255.digits # => [5, 5, 2] (dari satuan ke terbesar!)
255.digits(16) # => [15, 15] (dalam basis 16: 0xFF)
1234.digits # => [4, 3, 2, 1]
# Bits
5.to_s(2) # => "101" (representasi biner)
255.to_s(16) # => "ff" (representasi hex)
255.to_s(8) # => "377" (representasi oktal)
# Operasi bitwise
5 & 3 # => 1 (AND: 101 & 011 = 001)
5 | 3 # => 7 (OR: 101 | 011 = 111)
5 ^ 3 # => 6 (XOR: 101 ^ 011 = 110)
~5 # => -6 (NOT)
5 << 1 # => 10 (shift kiri: kalikan 2)
5 >> 1 # => 2 (shift kanan: bagi 2)
Bilangan Acak dengan Random #
Pembangkitan bilangan acak dibutuhkan untuk simulasi, pengacakan data, game, token keamanan, dan pengujian. Ruby menyediakan Random dan Kernel#rand dengan karakteristik berbeda.
# rand — cara paling sederhana
rand # => Float antara 0.0 dan 1.0 (eksklusif)
rand(10) # => Integer antara 0 dan 9 (inklusif 0, eksklusif 10)
rand(1..6) # => Integer antara 1 dan 6 (inklusif kedua ujung)
rand(1.0..2.0) # => Float antara 1.0 dan 2.0
# Random object — lebih kontrol, bisa di-seed
rng = Random.new(42) # seed tetap — hasil reproducible
rng.rand(100) # => selalu sama untuk seed yang sama
rng.rand(100) # => berbeda dari call sebelumnya, tapi deterministik
# Seed default
Random.new_seed # => integer acak dari OS
# Array#sample dan Array#shuffle — menggunakan RNG bawaan
[1, 2, 3, 4, 5].sample # => satu elemen acak
[1, 2, 3, 4, 5].sample(3) # => 3 elemen acak, tanpa duplikat
[1, 2, 3, 4, 5].shuffle # => array dengan urutan diacak
# Dengan seed tertentu untuk reproducibility
[1, 2, 3, 4, 5].shuffle(random: Random.new(42))
# => selalu menghasilkan urutan yang sama
# ANTI-PATTERN: menggunakan rand untuk token keamanan
def buat_token
rand(36**16).to_s(36) # JANGAN! PRNG tidak kriptografis
end
# BENAR: gunakan SecureRandom untuk kebutuhan keamanan
require 'securerandom'
SecureRandom.hex(16) # => "a3f2b1c4d5e6f7a8b9c0d1e2f3a4b5c6"
SecureRandom.urlsafe_base64 # => string URL-safe base64
SecureRandom.uuid # => "550e8400-e29b-41d4-a716-446655440000"
SecureRandom.random_number(100) # => Integer kriptografis, 0..99
flowchart TD
A[Butuh bilangan acak] --> B{Untuk keamanan?}
B -- Ya --> C["SecureRandom\n(kriptografis)"]
B -- Tidak --> D{Perlu reproducible?}
D -- Ya --> E["Random.new(seed)\nrng.rand(...)"]
D -- Tidak --> F["Kernel#rand\natau Array#sample"]
C --> G["SecureRandom.hex\nSecureRandom.uuid\nSecureRandom.random_number"]
E --> H[Hasil deterministik\ncocok untuk testing]
F --> I[Cepat, non-kriptografis]Float dan Presisi: Jebakan yang Harus Dipahami #
Floating-point adalah sistem representasi bilangan yang digunakan semua bahasa pemrograman modern, dan ia punya keterbatasan fundamental yang bisa menyebabkan bug yang sangat halus.
# Masalah presisi floating-point yang terkenal
0.1 + 0.2 # => 0.30000000000000004 (bukan 0.3!)
0.1 + 0.2 == 0.3 # => false !
# Kenapa? Float tidak bisa merepresentasikan 0.1 dan 0.2 secara exact
# dalam biner — persis seperti 1/3 tidak bisa ditulis exact dalam desimal
# Perbandingan Float yang aman — gunakan epsilon
def float_sama?(a, b, epsilon = 1e-10)
(a - b).abs < epsilon
end
float_sama?(0.1 + 0.2, 0.3) # => true
# Untuk kalkulasi keuangan — JANGAN gunakan Float!
harga = 0.1 + 0.2
puts harga # => 0.30000000000000004
# ANTI-PATTERN: Float untuk uang
total = 0.1 + 0.2
puts "Total: Rp #{(total * 100).round / 100.0}"
# BENAR: gunakan Integer (sen/poin) atau BigDecimal
total_sen = 10 + 20 # dalam sen: 10 sen + 20 sen
puts "Total: Rp #{total_sen / 100.0}" # => "Total: Rp 0.3"
BigDecimal untuk Presisi Tinggi #
Ketika ketepatan angka mutlak diperlukan — keuangan, perpajakan, akuntansi — BigDecimal adalah solusinya. Ia merepresentasikan angka desimal secara exact dengan presisi yang bisa dikontrol.
require 'bigdecimal'
require 'bigdecimal/util' # untuk method .to_d pada literal
# Membuat BigDecimal
a = BigDecimal("0.1")
b = BigDecimal("0.2")
(a + b).to_s # => "0.3E0"
(a + b) == BigDecimal("0.3") # => true (presisi exact!)
# Metode konversi — PENTING: selalu gunakan String, bukan Float!
BigDecimal("0.1") # BENAR: dari String
BigDecimal(0.1) # SALAH: dari Float sudah tidak presisi!
BigDecimal(0.1.to_s) # Boleh: konversi Float ke String dulu
# Dengan .to_d (butuh bigdecimal/util)
"0.1".to_d + "0.2".to_d # => 0.3e0
# Presisi operasi
BigDecimal("1") / BigDecimal("3")
# => 0.3333333333333333333333333333e0 (presisi default)
(BigDecimal("1") / BigDecimal("3")).round(10).to_s
# => "0.3333333333e0"
# Pembulatan dengan mode
require 'bigdecimal/math'
nilai = BigDecimal("2.5")
nilai.round(0, BigDecimal::ROUND_HALF_UP) # => 3
nilai.round(0, BigDecimal::ROUND_HALF_DOWN) # => 2
nilai.round(0, BigDecimal::ROUND_HALF_EVEN) # => 2 (banker's rounding)
# Contoh kalkulasi pajak yang benar
def hitung_pajak(harga_str, persen_pajak_str)
harga = BigDecimal(harga_str)
pajak = BigDecimal(persen_pajak_str) / 100
total_pajak = (harga * pajak).round(2, BigDecimal::ROUND_HALF_UP)
{
harga: harga,
pajak: total_pajak,
total: harga + total_pajak
}
end
hasil = hitung_pajak("150000.00", "11")
puts "Harga: Rp #{hasil[:harga]}" # Rp 0.15e6
puts "PPN: Rp #{hasil[:pajak]}" # Rp 0.165e5
puts "Total: Rp #{hasil[:total]}" # Rp 0.16515e6
Rational — Representasi Pecahan Exact #
Rational merepresentasikan bilangan sebagai pecahan pembilang/penyebut secara exact, tanpa kehilangan presisi. Berguna untuk matematika simbolis dan algoritma yang melibatkan pecahan.
# Membuat Rational
r = Rational(1, 3) # => (1/3)
r.to_f # => 0.3333333333333333
Rational(2, 4) # => (1/2) (otomatis disederhanakan)
Rational(3) # => (3/1)
# Operator dengan Rational
Rational(1, 3) + Rational(1, 6) # => (1/2) (exact!)
Rational(1, 3) * Rational(3, 4) # => (1/4)
Rational(2, 3) ** 2 # => (4/9)
# Konversi literal dengan sufiks r (Ruby 2.1+)
r = 1/3r # => (1/3) shortcut untuk Rational(1, 3)
3/4r # => (3/4)
# Perbandingan
Rational(1, 3) == Rational(2, 6) # => true (keduanya sama)
# Konversi
Rational(22, 7).to_f # => 3.142857142857143
Rational(22, 7).to_i # => 3 (truncate)
Statistik Dasar dengan Enumerable #
Ruby tidak punya modul statistik bawaan selengkap Python, tapi kombinasi Enumerable dengan operasi matematika bisa menghitung statistik dasar dengan sangat elegan.
data = [4, 8, 15, 16, 23, 42]
# Jumlah
data.sum # => 108
# Rata-rata
mean = data.sum.to_f / data.size # => 18.0
# Minimum dan maksimum
data.min # => 4
data.max # => 42
data.minmax # => [4, 42]
# Median
def median(arr)
sorted = arr.sort
mid = sorted.size / 2
sorted.size.odd? ? sorted[mid] : (sorted[mid-1] + sorted[mid]) / 2.0
end
median(data) # => 15.5
# Varians dan standar deviasi
def standar_deviasi(arr)
mean = arr.sum.to_f / arr.size
varians = arr.sum { |x| (x - mean) ** 2 } / arr.size
Math.sqrt(varians)
end
standar_deviasi(data).round(4) # => 12.2985
# Persentil
def persentil(arr, p)
sorted = arr.sort
indeks = (p / 100.0) * (sorted.size - 1)
bawah = sorted[indeks.floor]
atas = sorted[indeks.ceil]
bawah + (atas - bawah) * (indeks - indeks.floor)
end
persentil(data, 75).round(2) # => 23.75 (persentil ke-75)
Kapan Beralih ke Pendekatan Lain #
Tetap gunakan Math / Numeric bawaan jika:
✓ Komputasi trigonometri, logaritma, akar standar
✓ Operasi aritmetika integer dan float umum
✓ Pembulatan dan konversi tipe numerik
✓ Bilangan acak non-kriptografis
✓ Statistik dasar (mean, median, standar deviasi)
Pertimbangkan pendekatan lain jika:
✗ Kalkulasi keuangan / pajak — gunakan BigDecimal (selalu!)
✗ Bilangan acak untuk keamanan — gunakan SecureRandom
✗ Aljabar linear / matriks — gunakan gem numo-narray atau matrix stdlib
✗ Statistik kompleks — gunakan gem distribution atau statsample
✗ Komputasi simbolis — gunakan gem symengine atau manual Rational
✗ Komputasi numerik skala besar — pertimbangkan integrasi dengan Python/SciPy
Ringkasan #
Mathtidak perlurequire— langsung tersedia, semua method mengembalikanFloat, semua argumen trigonometri dalam radian.- Konversi derajat ke radian selalu diperlukan sebelum
sin/cos/tan— gunakansudut * Math::PI / 180; melewatkan konversi ini adalah kesalahan tersering dalam komputasi geometri.atan2(y, x)lebih baik dariatan(y/x)— menangani semua kuadran dengan benar dan tidak pernah membagi dengan nol.- Float tidak cocok untuk uang —
0.1 + 0.2 != 0.3bukan bug Ruby, tapi sifat IEEE 754; gunakanBigDecimalatau representasi integer (sen) untuk kalkulasi keuangan.BigDecimalharus diinisialisasi dari String —BigDecimal("0.1")benar,BigDecimal(0.1)salah karena Float sudah tidak presisi saat sampai ke konstruktor.SecureRandomuntuk token,Randomuntuk simulasi — jangan gunakanranduntuk kebutuhan kriptografis atau keamanan.Integer#gcddanInteger#lcmbawaan — tidak perlu implementasi manual; tersedia langsung dan efisien.Math.sqrt(-n)menghasilkanNaN, bukan exception — selalu cek input negatif sebelum memanggilsqrt, atau cek hasil dengan.nan?.- Pembulatan punya empat mode berbeda —
round,ceil,floor,truncateberperilaku berbeda untuk bilangan negatif; pilih yang tepat sesuai aturan bisnis, bukan secara default.require 'prime'untuk bilangan prima — tersedia di stdlib Ruby, tidak perlu gem eksternal untuk operasi prima dasar.
← Sebelumnya: IO