Numbers

Numbers #

Angka adalah fondasi hampir semua program — harga produk, koordinat GPS, hasil perhitungan ilmiah, statistik pengguna. Kotlin mewarisi sistem tipe numerik dari JVM tapi membungkusnya dengan API yang lebih bersih dan aman. Ada delapan tipe numerik bawaan, masing-masing dengan kapasitas dan trade-off yang berbeda. Pilihan tipe yang salah bisa menghasilkan overflow diam-diam, kehilangan presisi pada kalkulasi keuangan, atau performa yang buruk. Artikel ini membahas semua tipe numerik Kotlin secara mendalam: kapasitas dan batasannya, operasi aritmatika dan perilakunya, BigDecimal untuk presisi tinggi, fungsi matematika bawaan, cara memformat angka untuk tampilan, serta pola idiomatik yang membuat kode numerik lebih aman dan ekspresif.

Tipe Numerik dan Kapasitasnya #

Kotlin memiliki delapan tipe numerik: empat bilangan bulat, dua bilangan desimal, dan dua tipe khusus untuk karakter dan boolean.

flowchart TD
    A["Tipe Numerik Kotlin"] --> B["Bilangan Bulat\n(Integer)"]
    A --> C["Bilangan Desimal\n(Floating Point)"]
    B --> D["Byte\n8-bit\n-128 s/d 127"]
    B --> E["Short\n16-bit\n-32,768 s/d 32,767"]
    B --> F["Int\n32-bit\n-2.1M s/d 2.1M"]
    B --> G["Long\n64-bit\n-9.2 Kuadriliun s/d 9.2 Kuadriliun"]
    C --> H["Float\n32-bit\n~7 digit desimal"]
    C --> I["Double\n64-bit\n~15 digit desimal"]
TipeUkuranNilai MinimumNilai MaksimumKegunaan
Byte8-bit-128127Data biner, protokol jaringan
Short16-bit-32,76832,767Jarang dipakai
Int32-bit-2,147,483,6482,147,483,647Default untuk bilangan bulat
Long64-bit-9.2 × 10¹⁸9.2 × 10¹⁸ID besar, timestamp, jumlah besar
Float32-bit~1.4 × 10⁻⁴⁵~3.4 × 10³⁸Grafis, koordinat (presisi rendah)
Double64-bit~5.0 × 10⁻³²⁴~1.8 × 10³⁰⁸Default untuk desimal
// Literal numerik dan sufiksnya
val byteVal: Byte = 127
val shortVal: Short = 32_767
val intVal: Int = 2_147_483_647      // underscore untuk keterbacaan
val longVal: Long = 9_223_372_036_854_775_807L   // sufiks L wajib

val floatVal: Float = 3.14f          // sufiks f wajib
val doubleVal: Double = 3.14159265358979

// Literal dalam representasi berbeda
val hex = 0xFF           // 255 (hexadecimal)
val biner = 0b11111111   // 255 (binary)
val oktal = 0o377        // 255 (octal — Kotlin tidak mendukung, gunakan hex)

// Konstanta penting
println(Int.MAX_VALUE)      // 2,147,483,647
println(Int.MIN_VALUE)      // -2,147,483,648
println(Long.MAX_VALUE)     // 9,223,372,036,854,775,807
println(Double.MAX_VALUE)   // 1.7976931348623157E308
println(Double.MIN_VALUE)   // 5.0E-324 (nilai positif terkecil, bukan negatif terkecil)

Tipe Default dan Inferensi #

Kotlin memiliki tipe default untuk literal numerik: Int untuk bilangan bulat dan Double untuk desimal.

// Inferensi tipe otomatis
val a = 42          // Int
val b = 42L         // Long (sufiks L)
val c = 42.0        // Double
val d = 42.0f       // Float (sufiks f)
val e = 42.toByte() // Byte

// Inferensi dari konteks
fun terima(nilai: Long) = println(nilai)

terima(42)          // ERROR: Int tidak bisa implisit ke Long
terima(42L)         // OK
terima(42.toLong()) // OK

// Tapi dalam ekspresi aritmatika, ada promosi otomatis
val intNilai: Int = 100
val longNilai: Long = 200L
val hasil = intNilai + longNilai   // Int + Long = Long (promosi otomatis)
// Ini berbeda dari konversi — ini adalah ekspresi aritmatika, bukan assignment

Operasi Aritmatika dan Perilakunya #

Kotlin mendukung operator aritmatika standar, tapi ada beberapa perilaku yang perlu dipahami dengan baik.

Pembagian Integer #

// ANTI-PATTERN: mengira pembagian Int menghasilkan desimal
val hasil = 7 / 2          // 3, bukan 3.5!
val persentase = 1 / 3     // 0, bukan 0.333...

// BENAR: konversi ke Double sebelum membagi
val hasilDesimal = 7.0 / 2          // 3.5
val hasilDesimal2 = 7 / 2.0         // 3.5
val hasilDesimal3 = 7.toDouble() / 2  // 3.5

// Sisa pembagian (modulo)
val sisa = 17 % 5     // 2
val sisoNeg = -17 % 5  // -2 (tanda ikut dividend di Kotlin/JVM)

// floorDiv dan mod — perilaku berbeda untuk negatif
println((-17).floorDiv(5))   // -4 (berbeda dari -17 / 5 = -3)
println((-17).mod(5))        // 3 (selalu positif, berbeda dari % yang bisa negatif)

Overflow Integer #

// ANTI-PATTERN: tidak sadar overflow pada Int
val batas = Int.MAX_VALUE   // 2,147,483,647
val overflow = batas + 1    // -2,147,483,648 — wrap around silently!

// Contoh nyata yang berbahaya:
fun hitungTotal(harga: Int, jumlah: Int): Int {
    return harga * jumlah   // bisa overflow jika keduanya besar!
}

hitungTotal(100_000, 100_000)   // 10,000,000,000 > Int.MAX_VALUE → overflow!

// BENAR: gunakan Long untuk kalkulasi yang bisa besar
fun hitungTotal(harga: Long, jumlah: Long): Long {
    return harga * jumlah   // aman
}

// Atau deteksi overflow dengan Math.multiplyExact
fun hitungTotalSafe(harga: Int, jumlah: Int): Long {
    return harga.toLong() * jumlah.toLong()
}

Operasi Bitwise #

val a = 0b1010_1010   // 170
val b = 0b1100_1100   // 204

println(a and b)      // 0b1000_1000 = 136 (AND bitwise)
println(a or b)       // 0b1110_1110 = 238 (OR bitwise)
println(a xor b)      // 0b0110_0110 = 102 (XOR bitwise)
println(a.inv())      // inversi semua bit

println(a shl 2)      // geser kiri 2 bit = a * 4 = 680
println(a shr 2)      // geser kanan 2 bit = a / 4 = 42 (signed)
println(a ushr 2)     // geser kanan 2 bit (unsigned, isi dengan 0)

// Operasi bitwise berguna untuk flags dan masking
const val FLAG_AKTIF = 1 shl 0    // 0b0001
const val FLAG_ADMIN = 1 shl 1    // 0b0010
const val FLAG_PREMIUM = 1 shl 2  // 0b0100

var permissions = 0
permissions = permissions or FLAG_AKTIF or FLAG_PREMIUM  // set flags

val isAktif = (permissions and FLAG_AKTIF) != 0    // true
val isAdmin = (permissions and FLAG_ADMIN) != 0    // false
val isPremium = (permissions and FLAG_PREMIUM) != 0 // true

Floating Point dan Presisi #

Floating point adalah sumber bug yang sangat umum karena representasi biner tidak bisa merepresentasikan semua angka desimal dengan tepat.

// ANTI-PATTERN: perbandingan langsung floating point
val a = 0.1 + 0.2
println(a == 0.3)           // false! (0.1 + 0.2 = 0.30000000000000004)
println(a)                  // 0.30000000000000004

// BENAR: gunakan epsilon untuk perbandingan
val EPSILON = 1e-10
fun Double.hampirSamaDengan(lain: Double, eps: Double = EPSILON): Boolean {
    return Math.abs(this - lain) < eps
}

println((0.1 + 0.2).hampirSamaDengan(0.3))   // true

// Nilai khusus Float/Double
println(1.0 / 0.0)          // Infinity
println(-1.0 / 0.0)         // -Infinity
println(0.0 / 0.0)          // NaN (Not a Number)

val nan = Double.NaN
println(nan == nan)          // false! NaN tidak sama dengan dirinya sendiri
println(nan.isNaN())         // true — cara yang benar untuk cek NaN
println(Double.POSITIVE_INFINITY.isInfinite())  // true

// ANTI-PATTERN: tidak cek NaN atau Infinity sebelum digunakan
fun hitungRasio(pembilang: Double, penyebut: Double): Double {
    return pembilang / penyebut   // bisa NaN atau Infinity!
}

// BENAR: validasi dan tangani kasus khusus
fun hitungRasio(pembilang: Double, penyebut: Double): Double? {
    if (penyebut == 0.0) return null
    val hasil = pembilang / penyebut
    return if (hasil.isFinite()) hasil else null
}

BigDecimal — Presisi Tinggi untuk Keuangan #

Double dan Float tidak cocok untuk kalkulasi keuangan karena ketidakpresisian floating point. Gunakan BigDecimal untuk angka yang membutuhkan presisi tepat.

import java.math.BigDecimal
import java.math.MathContext
import java.math.RoundingMode

// Masalah dengan Double untuk keuangan
val harga = 19.99
val pajak = 0.11
val total = harga + harga * pajak
println(total)   // 22.1889 — mungkin 22.18890000000000... di dalamnya

// BENAR: BigDecimal untuk keuangan
val hargaBD = BigDecimal("19.99")     // SELALU gunakan String, bukan Double!
val pajakBD = BigDecimal("0.11")
val totalBD = hargaBD + hargaBD * pajakBD
println(totalBD)   // 22.1889 — tepat

// ANTI-PATTERN: BigDecimal dari Double
val salah = BigDecimal(0.1)     // 0.1000000000000000055511151231257827021181583404541015625
val benar = BigDecimal("0.1")   // 0.1

// Operasi BigDecimal
val a = BigDecimal("100.50")
val b = BigDecimal("33.33")

val tambah = a + b              // 133.83
val kurang = a - b              // 67.17
val kali = a * b                // 3349.665
val bagi = a.divide(b, 2, RoundingMode.HALF_UP)  // 3.02

// Pembulatan
val nilai = BigDecimal("123.456789")
val bulatDua = nilai.setScale(2, RoundingMode.HALF_UP)   // 123.46
val bulatNol = nilai.setScale(0, RoundingMode.HALF_UP)   // 123

// Mode pembulatan yang tersedia
RoundingMode.HALF_UP    // 2.5 → 3 (konvensional)
RoundingMode.HALF_DOWN  // 2.5 → 2
RoundingMode.HALF_EVEN  // 2.5 → 2, 3.5 → 4 (banker's rounding)
RoundingMode.CEILING    // selalu ke atas: 2.1 → 3
RoundingMode.FLOOR      // selalu ke bawah: 2.9 → 2
RoundingMode.UP         // menjauh dari nol: -2.1 → -3
RoundingMode.DOWN       // menuju nol: -2.9 → -2

// Perbandingan BigDecimal — gunakan compareTo, bukan equals!
val x = BigDecimal("2.0")
val y = BigDecimal("2.00")

println(x == y)              // false! (scale berbeda: 1 vs 2)
println(x.compareTo(y) == 0) // true — nilai matematisnya sama

// Extension functions untuk kemudahan
fun Double.toBigDecimalSafe() = toBigDecimal().setScale(2, RoundingMode.HALF_UP)
fun Long.toRupiah() = BigDecimal(this).setScale(0)

Kalkulasi Keuangan Lengkap #

data class ItemPesanan(val nama: String, val harga: BigDecimal, val jumlah: Int)

fun hitungTotalPesanan(
    items: List<ItemPesanan>,
    diskonPersen: BigDecimal = BigDecimal.ZERO,
    pajakPersen: BigDecimal = BigDecimal("0.11")
): Map<String, BigDecimal> {
    val subtotal = items.fold(BigDecimal.ZERO) { acc, item ->
        acc + item.harga * BigDecimal(item.jumlah)
    }

    val diskon = subtotal * diskonPersen / BigDecimal("100")
    val setelahDiskon = subtotal - diskon
    val pajak = setelahDiskon * pajakPersen
    val total = setelahDiskon + pajak

    return mapOf(
        "subtotal" to subtotal.setScale(2, RoundingMode.HALF_UP),
        "diskon" to diskon.setScale(2, RoundingMode.HALF_UP),
        "setelahDiskon" to setelahDiskon.setScale(2, RoundingMode.HALF_UP),
        "pajak" to pajak.setScale(2, RoundingMode.HALF_UP),
        "total" to total.setScale(2, RoundingMode.HALF_UP)
    )
}

val items = listOf(
    ItemPesanan("Laptop", BigDecimal("15000000"), 1),
    ItemPesanan("Mouse", BigDecimal("250000"), 2),
    ItemPesanan("Keyboard", BigDecimal("800000"), 1)
)

val rincian = hitungTotalPesanan(items, diskonPersen = BigDecimal("10"))
// subtotal      → 16,300,000.00
// diskon        → 1,630,000.00
// setelahDiskon → 14,670,000.00
// pajak         → 1,613,700.00
// total         → 16,283,700.00

Fungsi Matematika #

Kotlin Standard Library menyediakan fungsi matematika melalui kotlin.math — tidak perlu import java.lang.Math secara eksplisit.

import kotlin.math.*

// Fungsi dasar
println(abs(-42))          // 42
println(abs(-3.14))        // 3.14
println(sqrt(16.0))        // 4.0
println(cbrt(27.0))        // 3.0 (akar pangkat 3)
println(pow(2.0, 10.0))    // 1024.0
println(2.0.pow(10.0))     // 1024.0 (versi extension)

// Pembulatan
println(floor(3.7))        // 3.0 (ke bawah)
println(ceil(3.2))         // 4.0 (ke atas)
println(round(3.5))        // 4 (ke terdekat, .5 ke atas)
println(truncate(3.9))     // 3.0 (potong desimal)

// Logaritma dan eksponensial
println(ln(E))             // 1.0 (natural log)
println(log10(1000.0))     // 3.0
println(log2(1024.0))      // 10.0
println(log(8.0, 2.0))     // 3.0 (log basis kustom)
println(exp(1.0))          // 2.718... (e^1)

// Trigonometri (dalam radian)
println(sin(PI / 2))       // 1.0
println(cos(0.0))          // 1.0
println(tan(PI / 4))       // 1.0 (sekitar, karena floating point)
println(asin(1.0))         // PI/2 = 1.5707...
println(atan2(1.0, 1.0))   // PI/4 = 0.7853...

// Konstanta
println(PI)                // 3.141592653589793
println(E)                 // 2.718281828459045

// min dan max
println(min(3, 7))         // 3
println(max(3.14, 2.71))   // 3.14
println(min(3, 7, 1, 5))   // tidak ada — Kotlin tidak punya min vararg
println(listOf(3, 7, 1, 5).min())  // 1 — gunakan collection

Fungsi Matematika Praktis #

// Jarak antara dua titik (Euclidean distance)
data class Titik(val x: Double, val y: Double)

fun jarak(a: Titik, b: Titik): Double {
    val dx = a.x - b.x
    val dy = a.y - b.y
    return sqrt(dx * dx + dy * dy)
    // atau: hypot(dx, dy) — lebih akurat untuk nilai ekstrem
}

// Bulatkan ke kelipatan tertentu
fun bulatKeKelipatan(nilai: Int, kelipatan: Int): Int {
    return ((nilai + kelipatan - 1) / kelipatan) * kelipatan
}

bulatKeKelipatan(17, 5)   // 20
bulatKeKelipatan(20, 5)   // 20
bulatKeKelipatan(21, 5)   // 25

// Nilai dalam rentang (clamp)
fun Double.clamp(min: Double, max: Double) = coerceIn(min, max)

3.7.clamp(0.0, 3.0)    // 3.0
(-1.5).clamp(0.0, 1.0) // 0.0
0.5.clamp(0.0, 1.0)    // 0.5

// Interpolasi linear
fun lerp(start: Double, end: Double, t: Double): Double {
    return start + (end - start) * t.coerceIn(0.0, 1.0)
}

lerp(0.0, 100.0, 0.0)    // 0.0
lerp(0.0, 100.0, 0.5)    // 50.0
lerp(0.0, 100.0, 1.0)    // 100.0
lerp(0.0, 100.0, 0.75)   // 75.0

Formatting Angka #

Menampilkan angka dengan format yang tepat adalah keterampilan penting, terutama untuk aplikasi yang menghadapi pengguna.

import java.text.NumberFormat
import java.util.Locale

// Format dasar dengan String
val n = 1_234_567.89

// Kotlin string templates — cocok untuk format sederhana
println("Nilai: $n")                        // Nilai: 1234567.89
println("Nilai: %.2f".format(n))            // Nilai: 1234567.89
println("Nilai: %,.2f".format(n))           // Nilai: 1,234,567.89 (dengan separator)
println("Persen: %.1f%%".format(85.5))      // Persen: 85.5%
println("Hex: %X".format(255))              // Hex: FF
println("Padding: %10d".format(42))         // Padding:         42 (lebar 10)
println("Padding: %-10d|".format(42))       // Padding: 42        | (rata kiri)
println("Zero pad: %05d".format(42))        // Zero pad: 00042

// NumberFormat — untuk format sesuai locale
val localeID = Locale("id", "ID")
val formatRupiah = NumberFormat.getCurrencyInstance(localeID)
println(formatRupiah.format(15_000_000.0))  // Rp15.000.000,00

val formatAngka = NumberFormat.getNumberInstance(localeID)
println(formatAngka.format(1_234_567.89))   // 1.234.567,89

// Locale berbeda untuk perbandingan
val formatUS = NumberFormat.getCurrencyInstance(Locale.US)
println(formatUS.format(15_000_000.0))      // $15,000,000.00

// Format persentase
val formatPersen = NumberFormat.getPercentInstance()
formatPersen.minimumFractionDigits = 1
println(formatPersen.format(0.1234))        // 12.3%

// Extension function untuk Rupiah — berguna di proyek Indonesia
fun Double.formatRupiah(): String {
    val format = NumberFormat.getCurrencyInstance(Locale("id", "ID"))
    return format.format(this)
}

fun Long.formatRupiah(): String = toDouble().formatRupiah()

fun Double.formatPersen(desimal: Int = 1): String =
    "%.${desimal}f%%".format(this * 100)

println(15_000_000.0.formatRupiah())   // Rp15.000.000,00
println(0.856.formatPersen())          // 85.6%
println(0.856.formatPersen(2))        // 85.60%

Unsigned Integers #

Kotlin mendukung unsigned integers sejak versi 1.5 — berguna untuk bekerja dengan data biner, protokol jaringan, atau saat nilai negatif tidak bermakna.

// Tipe unsigned
val uByte: UByte = 255u          // 0 s/d 255
val uShort: UShort = 65_535u     // 0 s/d 65,535
val uInt: UInt = 4_294_967_295u  // 0 s/d 4,294,967,295
val uLong: ULong = 18_446_744_073_709_551_615u  // 0 s/d 2^64-1

// Perbandingan dengan signed
val signed: Int = -1
val unsigned: UInt = signed.toUInt()
println(unsigned)   // 4294967295 — interpretasi sebagai unsigned

// Konversi
val u: UInt = 100u
val s: Int = u.toInt()   // 100
val uDariS: UInt = 100.toUInt()

// Operasi — sama seperti tipe signed
val a: UInt = 10u
val b: UInt = 3u
println(a + b)   // 13
println(a - b)   // 7
println(a * b)   // 30
println(a / b)   // 3
println(a % b)   // 1

// Berguna untuk port number, file size, checksum
val portNumber: UShort = 8080u
val fileSize: ULong = 1_073_741_824u   // 1 GB dalam byte
val checksum: UInt = hitungCRC32(data)
Unsigned integers di Kotlin masih merupakan inline classes yang di-compile ke tipe signed di JVM. Ini berarti ada sedikit overhead saat digunakan sebagai generics atau nullable. Untuk performa kritis di JVM, pertimbangkan tetap menggunakan Long sebagai pengganti UInt.

Pola Idiomatik untuk Numerik #

Hindari Magic Numbers #

// ANTI-PATTERN: magic numbers yang tidak bermakna
fun hitungGaji(jam: Int, lembur: Int): Double {
    return (jam * 50_000 + lembur * 75_000).toDouble()
}

// BENAR: konstanta bernama
const val TARIF_JAM_NORMAL = 50_000L
const val TARIF_JAM_LEMBUR = 75_000L

fun hitungGaji(jam: Int, lembur: Int): Long {
    return jam * TARIF_JAM_NORMAL + lembur * TARIF_JAM_LEMBUR
}

Gunakan Long untuk Uang dalam Satuan Terkecil #

// Pola yang digunakan industri keuangan: simpan dalam satuan terkecil
// Rp 15.000 disimpan sebagai 1_500_000 (dalam sen/paisa)
// USD 19.99 disimpan sebagai 1999 (dalam cent)

data class Uang(val jumlah: Long, val satuan: String = "IDR") {
    // jumlah dalam unit terkecil (sen)
    val rupiah: Double get() = jumlah / 100.0

    operator fun plus(lain: Uang): Uang {
        require(satuan == lain.satuan) { "Tidak bisa menjumlahkan mata uang berbeda" }
        return Uang(jumlah + lain.jumlah, satuan)
    }

    operator fun times(faktor: Int) = Uang(jumlah * faktor, satuan)

    fun format(): String = "Rp ${"%,.0f".format(rupiah)}"
}

val harga = Uang(1_500_000)      // Rp 15.000,00
val ongkir = Uang(1_500_000)     // Rp 15.000,00
val total = (harga + ongkir) * 2
println(total.format())           // Rp 60.000

Statistik Sederhana #

// Fungsi statistik yang reusable
fun List<Double>.rata(): Double = if (isEmpty()) 0.0 else sum() / size

fun List<Double>.median(): Double {
    if (isEmpty()) return 0.0
    val terurut = sorted()
    val tengah = size / 2
    return if (size % 2 == 0) {
        (terurut[tengah - 1] + terurut[tengah]) / 2.0
    } else {
        terurut[tengah]
    }
}

fun List<Double>.varians(): Double {
    val mean = rata()
    return map { (it - mean).pow(2) }.rata()
}

fun List<Double>.stdDev(): Double = sqrt(varians())

val data = listOf(2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0)
println(data.rata())    // 5.0
println(data.median())  // 4.5
println(data.varians()) // 4.0
println(data.stdDev())  // 2.0

Kapan Menggunakan Tipe Numerik yang Mana #

Gunakan Int jika:
  ✓ Default — cukup untuk sebagian besar hitungan
  ✓ Indeks, counter, jumlah item, umur, tahun
  ✓ Nilai dijamin tidak melebihi ~2 miliar

Gunakan Long jika:
  ✓ Timestamp (milidetik sejak epoch)
  ✓ ID database yang besar (auto-increment besar)
  ✓ Ukuran file dalam byte
  ✓ Total uang dalam satuan terkecil
  ✓ Hasil perkalian dua Int yang mungkin overflow

Gunakan Double jika:
  ✓ Koordinat GPS, koordinat grafis
  ✓ Hasil perhitungan saintifik
  ✓ Persentase, rasio, rata-rata
  ✗ Hindari untuk kalkulasi keuangan

Gunakan BigDecimal jika:
  ✓ Harga, gaji, pajak, diskon
  ✓ Kalkulasi akuntansi apapun
  ✓ Nilai yang harus tepat, bukan aproximasi

Gunakan Float hanya jika:
  ✓ Bekerja dengan API grafis (OpenGL, shader)
  ✓ Performa dan memori kritis, presisi rendah cukup
  ✗ Hindari untuk kalkulasi umum — gunakan Double

Ringkasan #

  • Delapan tipe numerik: Byte, Short, Int, Long untuk bilangan bulat; Float, Double untuk desimal. Int dan Double adalah default yang paling sering digunakan.
  • Tidak ada implicit widening — setiap konversi numerik harus eksplisit dengan .toLong(), .toDouble(), dll. Ini mencegah bug dari konversi tak terduga.
  • Pembagian integer selalu integer7 / 2 = 3, bukan 3.5. Konversi salah satu operand ke Double terlebih dahulu jika butuh hasil desimal.
  • Overflow integer diam-diamInt.MAX_VALUE + 1 menghasilkan Int.MIN_VALUE tanpa error. Gunakan Long untuk kalkulasi yang bisa melampaui ~2 miliar.
  • Floating point tidak presisi0.1 + 0.2 ≠ 0.3 dalam representasi biner. Gunakan epsilon untuk perbandingan, atau BigDecimal untuk presisi penuh.
  • BigDecimal untuk keuangan — selalu inisialisasi dari String (BigDecimal("19.99")), bukan Double (BigDecimal(19.99) yang sudah tidak presisi). Gunakan RoundingMode.HALF_UP untuk pembulatan konvensional.
  • Perbandingan BigDecimal harus menggunakan .compareTo() == 0, bukan == — karena BigDecimal("2.0") != BigDecimal("2.00") meski nilainya sama.
  • kotlin.math menyediakan semua fungsi matematika: sqrt, abs, pow, log, fungsi trigonometri, dan konstanta PI, E.
  • Formatting dengan "%.2f".format(nilai) untuk format sederhana, NumberFormat dengan Locale untuk format sesuai regional (termasuk Rupiah).
  • Simpan uang dalam satuan terkecil (sen, paisa) sebagai Long — lebih aman dari floating point dan menghindari masalah pembulatan dalam kalkulasi keuangan.

← Sebelumnya: Type Conversion   Berikutnya: Characters →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact