1. Pengantar
Pustaka Decimal Go adalah alat yang powerful untuk menangani desimal titik tetap presisi sembarang dalam bahasa Go. Ini memungkinkan operasi penambahan, pengurangan, perkalian, dan pembagian tanpa kehilangan presisi. Selain itu, pustaka ini menyediakan fungsionalitas seperti serialisasi/deserialisasi database/SQL, serta serialisasi/deserialisasi JSON/XML.
2. Instalasi
Untuk menginstal pustaka Decimal Go, Anda dapat menggunakan perintah berikut:
go get github.com/shopspring/decimal
Harap dicatat bahwa pustaka Decimal memerlukan versi Go >=1.7.
3. Penggunaan Dasar
Untuk menggunakan pustaka Decimal dalam program Go, impor paket "github.com/shopspring/decimal". Berikut contoh kode sederhana yang menunjukkan penggunaan dasar:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
price, err := decimal.NewFromString("136.02")
if err != nil {
panic(err)
}
quantity := decimal.NewFromInt(3)
fee, _ := decimal.NewFromString(".035")
taxRate, _ := decimal.NewFromString(".08875")
subtotal := price.Mul(quantity)
preTax := subtotal.Mul(fee).Add(decimal.NewFromFloat(1))
total := preTax.Mul(taxRate).Add(decimal.NewFromFloat(1))
fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
fmt.Println("Pre-tax:", preTax) // Pre-tax: 422.3421
fmt.Println("Taxes:", total.Sub(preTax)) // Taxes: 37.482861375
fmt.Println("Total:", total) // Total: 459.824961375
fmt.Println("Tax rate:", total.Sub(preTax).Div(preTax)) // Tax rate: 0.08875
}
4. Membuat Variabel Decimal
Pustaka Decimal menyediakan berbagai metode untuk membuat variabel Decimal. Berikut adalah API yang didukung:
-
decimal.NewFromBigInt(value *big.Int, exp int32) Decimal
-
decimal.NewFromFloat(value float64) Decimal
-
decimal.NewFromFloat32(value float32) Decimal
-
decimal.NewFromFloatWithExponent(value float64, exp int32) Decimal
-
decimal.NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error)
-
decimal.NewFromInt(value int64) Decimal
-
decimal.NewFromInt32(value int32) Decimal
-
decimal.NewFromString(value string) (Decimal, error)
-
decimal.RequireFromString(value string) Decimal
5. Operasi Aritmatika
Pustaka Decimal Go menyediakan beberapa operasi aritmatika yang dapat dilakukan pada variabel Decimal. Berikut beberapa operasi yang didukung:
-
Add(d2 Decimal) Decimal
: Menambahkan dua nilai Decimal dan mengembalikan hasilnya. -
Sub(d2 Decimal) Decimal
: Mengurangkan satu nilai Decimal dari nilai lainnya dan mengembalikan hasilnya. -
Div(d2 Decimal) Decimal
: Membagi satu nilai Decimal dengan nilai lain dan mengembalikan hasilnya. -
DivRound(d2 Decimal, precision int32) Decimal
: Membagi satu nilai Decimal dengan nilai lain dan mengembalikan hasilnya dengan presisi yang ditentukan. -
Mod(d2 Decimal) Decimal
: Menghitung modulus (sisa bagi) dari satu nilai Decimal dibagi dengan nilai lain dan mengembalikan hasilnya. -
Mul(d2 Decimal) Decimal
: Mengalikan dua nilai Decimal dan mengembalikan hasilnya.
Anda dapat menggunakan operasi-operasi ini untuk melakukan perhitungan aritmatika umum pada nilai Decimal. Berikut contoh yang menunjukkan penggunaan operasi-operasi ini:
price, _ := decimal.NewFromString("136.02")
quantity := decimal.NewFromInt(3)
subtotal := price.Mul(quantity)
tax := subtotal.Mul(decimal.NewFromFloat(0.08875))
total := subtotal.Add(tax)
fmt.Println("Subtotal:", subtotal) // Subtotal: 408.06
fmt.Println("Tax:", tax) // Tax: 36.244985
fmt.Println("Total:", total) // Total: 444.304985
Pada contoh di atas, kami menggunakan metode Mul()
untuk menghitung subtotal
dengan mengalikan price
dan quantity
. Kemudian kami menghitung tax
dengan mengalikan subtotal
dengan tarif pajak. Akhirnya, kami menghitung total
dengan menambahkan subtotal
dan tax
menggunakan metode Add()
.
6. Operasi Pembulatan
Library Go Decimal menyediakan beberapa operasi pembulatan yang dapat digunakan untuk membulatkan nilai Decimal ke presisi tertentu. Berikut adalah beberapa operasi pembulatan yang tersedia:
-
Round(places int32) Decimal
: Membulatkan desimal ke jumlah tempat desimal yang ditentukan. -
RoundBank(places int32) Decimal
: Membulatkan desimal menggunakan pembulatan banker ke jumlah tempat desimal yang ditentukan. -
RoundCash(interval uint8) Decimal
: Membulatkan desimal ke interval tertentu, seperti 5 sen, 10 sen, 25 sen, 50 sen, atau 1 dolar. -
RoundCeil(places int32) Decimal
: Membulatkan desimal ke positif tak hingga. -
RoundDown(places int32) Decimal
: Membulatkan desimal ke nol. -
RoundFloor(places int32) Decimal
: Membulatkan desimal ke negatif tak hingga. -
RoundUp(places int32) Decimal
: Membulatkan desimal menjauh dari nol.
6.1. Round
Round membulatkan desimal ke jumlah tempat desimal yang ditentukan. Jika places < 0, maka akan membulatkan bagian bilangan bulat ke 10^(-places) terdekat.
NewFromFloat(5.45).Round(1).String() // Output: "5.5"
NewFromFloat(545).Round(-1).String() // Output: "550"
6.2. RoundBank
RoundBank membulatkan desimal ke jumlah tempat desimal yang ditentukan. Jika jarak antara digit terakhir yang akan dibulatkan dan dua bilangan bulat terdekat sama, nilai yang dibulatkan akan mengambil bilangan genap.
Jika places < 0, maka bagian bilangan bulat akan dibulatkan ke 10^(-places) terdekat.
NewFromFloat(5.45).RoundBank(1).String() // Output: "5.4"
NewFromFloat(545).RoundBank(-1).String() // Output: "540"
NewFromFloat(5.46).RoundBank(1).String() // Output: "5.5"
NewFromFloat(546).RoundBank(-1).String() // Output: "550"
NewFromFloat(5.55).RoundBank(1).String() // Output: "5.6"
NewFromFloat(555).RoundBank(-1).String() // Output: "560"
6.3. RoundCash
RoundCash (juga dikenal dengan nama pembulatan uang/penny/Ireland) membulatkan desimal ke interval tertentu. Jumlah pembayaran dari transaksi tunai akan dibulatkan ke kelipatan terdekat dari satuan mata uang terkecil. Interval yang tersedia adalah: 5, 10, 25, 50, dan 100; angka lain akan menyebabkan pengecualian.
5: pembulatan 5 sen 3.43 => 3.45
10: pembulatan 10 sen 3.45 => 3.50 (5 dibulatkan ke atas)
25: pembulatan 25 sen 3.41 => 3.50
50: pembulatan 50 sen 3.75 => 4.00
100: pembulatan 100 sen 3.50 => 4.00
6.4. RoundCeil
RoundCeil membulatkan desimal ke positif tak hingga.
NewFromFloat(545).RoundCeil(-2).String() // Output: "600"
NewFromFloat(500).RoundCeil(-2).String() // Output: "500"
NewFromFloat(1.1001).RoundCeil(2).String() // Output: "1.11"
NewFromFloat(-1.454).RoundCeil(1).String() // Output: "-1.5"
6.5. RoundDown
RoundDown membulatkan desimal ke nol.
NewFromFloat(545).RoundDown(-2).String() // Output: "500"
NewFromFloat(-500).RoundDown(-2).String() // Output: "-500"
NewFromFloat(1.1001).RoundDown(2).String() // Output: "1.1"
NewFromFloat(-1.454).RoundDown(1).String() // Output: "-1.5"
6.6. RoundFloor
RoundFloor membulatkan desimal ke nol negatif.
NewFromFloat(545).RoundFloor(-2).String() // Output: "500"
NewFromFloat(-500).RoundFloor(-2).String() // Output: "-500"
NewFromFloat(1.1001).RoundFloor(2).String() // Output: "1.1"
NewFromFloat(-1.454).RoundFloor(1).String() // Output: "-1.4"
6.7. RoundUp
RoundUp membulatkan desimal menjauhi nol.
NewFromFloat(545).RoundUp(-2).String() // Output: "600"
NewFromFloat(500).RoundUp(-2).String() // Output: "500"
NewFromFloat(1.1001).RoundUp(2).String() // Output: "1.11"
NewFromFloat(-1.454).RoundUp(1).String() // Output: "-1.4"
7. Mengonversi Tipe Decimal ke String
Pustaka Go Decimal menyediakan metode untuk mengonversi nilai Decimal ke representasi string. Berikut beberapa metode yang tersedia:
-
String(): string
: Mengembalikan representasi string dari angka desimal dengan titik desimal tetap. -
StringFixed(places int32) string
: Mengembalikan representasi string yang dibulatkan dengan jumlah tempat desimal yang ditentukan. -
StringFixedBank(places int32) string
: Mengembalikan representasi string yang dibulatkan (pembulatan bankir) dengan jumlah tempat desimal yang ditentukan.
Anda dapat memilih metode yang sesuai sesuai kebutuhan. Berikut contoh mengonversi angka desimal menjadi string:
d := decimal.NewFromFloat(5.45)
str := d.String()
fmt.Println("Representasi string dari angka desimal:", str) // Representasi string dari angka desimal: 5.45
// Contoh StringFixed
NewFromFloat(0).StringFixed(2) // Output: "0.00"
NewFromFloat(0).StringFixed(0) // Output: "0"
NewFromFloat(5.45).StringFixed(0) // Output: "5"
NewFromFloat(5.45).StringFixed(1) // Output: "5.5"
NewFromFloat(5.45).StringFixed(2) // Output: "5.45"
NewFromFloat(5.45).StringFixed(3) // Output: "5.450"
NewFromFloat(545).StringFixed(-1) // Output: "550"
// Contoh StringFixedBank
NewFromFloat(0).StringFixedBank(2) // Output: "0.00"
NewFromFloat(0).StringFixedBank(0) // Output: "0"
NewFromFloat(5.45).StringFixedBank(0) // Output: "5"
NewFromFloat(5.45).StringFixedBank(1) // Output: "5.4"
NewFromFloat(5.45).StringFixedBank(2) // Output: "5.45"
NewFromFloat(5.45).StringFixedBank(3) // Output: "5.450"
NewFromFloat(545).StringFixedBank(-1) // Output: "540"
8. Pertanyaan Umum
Q: Mengapa tidak menggunakan float64 secara langsung? A: float64 tidak dapat mewakili angka seperti 0.1 dengan akurat, yang dapat menyebabkan kesalahan kecil. Dalam situasi yang melibatkan perhitungan keuangan, kesalahan-kesalahan ini dapat bertambah dari waktu ke waktu dan menimbulkan masalah signifikan.
Q: Mengapa tidak menggunakan big.Rat secara langsung? A: Meskipun big.Rat dapat mewakili angka rasional, itu tidak cocok untuk mewakili mata uang. Angka desimal lebih baik untuk perhitungan keuangan karena mereka dapat mewakili pecahan desimal secara akurat tanpa kehilangan presisi.
Q: Mengapa API-nya tidak mirip dengan big.Int? A: API dari pustaka Decimal memprioritaskan kegunaan dan kebenaran daripada kinerja. Sementara API dari big.Int mengurangi alokasi memori atas alasan kinerja, hal ini dapat menyebabkan kode yang kompleks dan rentan terhadap kesalahan. API dari pustaka Decimal dirancang agar sederhana dan mudah dipahami.