Math

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 / MethodNilaiKeterangan
Math::PI3.14159265358979…π — rasio keliling terhadap diameter lingkaran
Math::E2.71828182845904…Bilangan Euler — basis logaritma natural
Float::INFINITYTak hingga positif
Float::NANNaNNot a Number — hasil operasi tidak terdefinisi
Float::EPSILON2.22e-16Selisih terkecil antara dua Float berbeda
Float::DIG15Jumlah 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 --> D
27 ** (1.0/3) seharusnya menghasilkan tepat 3.0, tapi karena 1.0/3 adalah 0.3333... dalam floating-point, hasilnya bisa 2.9999999999999996 di 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 --> G
Math.log(0) menghasilkan -Infinity, dan Math.log(-1) menghasilkan NaN. 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
Method3.7-3.7Prinsip
round4-4Ke terdekat, setengah menjauhi nol
ceil4-3Selalu ke atas (→ +∞)
floor3-4Selalu ke bawah (→ -∞)
truncate3-3Selalu 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 #

  • Math tidak perlu require — langsung tersedia, semua method mengembalikan Float, semua argumen trigonometri dalam radian.
  • Konversi derajat ke radian selalu diperlukan sebelum sin/cos/tan — gunakan sudut * Math::PI / 180; melewatkan konversi ini adalah kesalahan tersering dalam komputasi geometri.
  • atan2(y, x) lebih baik dari atan(y/x) — menangani semua kuadran dengan benar dan tidak pernah membagi dengan nol.
  • Float tidak cocok untuk uang0.1 + 0.2 != 0.3 bukan bug Ruby, tapi sifat IEEE 754; gunakan BigDecimal atau representasi integer (sen) untuk kalkulasi keuangan.
  • BigDecimal harus diinisialisasi dari StringBigDecimal("0.1") benar, BigDecimal(0.1) salah karena Float sudah tidak presisi saat sampai ke konstruktor.
  • SecureRandom untuk token, Random untuk simulasi — jangan gunakan rand untuk kebutuhan kriptografis atau keamanan.
  • Integer#gcd dan Integer#lcm bawaan — tidak perlu implementasi manual; tersedia langsung dan efisien.
  • Math.sqrt(-n) menghasilkan NaN, bukan exception — selalu cek input negatif sebelum memanggil sqrt, atau cek hasil dengan .nan?.
  • Pembulatan punya empat mode berbedaround, ceil, floor, truncate berperilaku 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
About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact