Jangan Simpan Uang dengan float64

·Abdul Wahid Kahar

Waktu pertama kali implement wallet di project Go saya, saya pakai float64 untuk kolom balance dan amount. Kelihatannya wajar — uang punya desimal, float punya desimal.

Tapi masalahnya muncul segera. Coba jalankan ini:

go
var a float64 = 0.1
var b float64 = 0.2
fmt.Println(a + b) // 0.30000000000000004

Ini bukan bug Go. Ini sifat dasar float di semua bahasa pemrograman. Float menyimpan angka dalam format binary, dan tidak semua desimal bisa direpresentasikan secara exact dalam binary. 0.1 dalam binary adalah angka yang tidak pernah berhenti — seperti 1/3 dalam desimal yang hasilnya 0.3333...

Di satu transaksi, selisihnya kelihatan tidak berarti. Tapi di sistem yang proses jutaan transaksi per hari, selisih kecil itu accumulated. Uang bisa "hilang" atau "lebih" di pembukuan tanpa ada yang tahu kenapa.

Solusinya: simpan uang sebagai int64 dalam satuan terkecil.

Rp100.000 disimpan sebagai 100000. Rupiah tidak punya subunit seperti sen di Dollar — jadi angka yang disimpan sama dengan nilai Rupiahnya, tapi dalam bentuk integer. Integer tidak punya floating point error — 100000 + 200000 selalu 300000, tidak pernah 300000.0000000004

Di database, pakai BIGINT. Di Go, pakai int64. Konversi ke tampilan Rupiah hanya dilakukan di layer presentasi — bukan di kalkulasi.

go
// simpan dalam sen
balance int64 // 1000000 = Rp10.000

// tampilkan ke user
fmt.Printf("Rp%.0f", float64(balance)/100)

Ini yang dipakai Stripe dan hampir semua sistem finansial modern. Bukan karena canggih — tapi karena benar.

Referensi: Stripe API Documentation — https://docs.stripe.com/api/prices/create