1. Giriş
Go Decimal kütüphanesi, Go dilinde keyfi hassasiyette sabit noktalı ondalıkları işlemek için güçlü bir araçtır. Kesinliği kaybetmeden toplama, çıkarma, çarpma ve bölme işlemlerine olanak tanır. Ayrıca, veritabanı/SQL serileştirme/deserileştirme ile JSON/XML serileştirme/deserileştirme gibi işlevsellikler sunar.
2. Kurulum
Go Decimal kütüphanesini yüklemek için aşağıdaki komutu kullanabilirsiniz:
go get github.com/shopspring/decimal
Lütfen Decimal kütüphanesinin Go sürümü >=1.7 gerektirdiğini unutmayın.
3. Temel Kullanım
Go programında Decimal kütüphanesini kullanmak için "github.com/shopspring/decimal" paketini içe aktarın. Temel kullanımı gösteren basit bir örnek kod aşağıda verilmiştir:
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("Ara Toplam:", subtotal) // Ara Toplam: 408.06
fmt.Println("Vergi Öncesi:", preTax) // Vergi Öncesi: 422.3421
fmt.Println("Vergiler:", total.Sub(preTax)) // Vergiler: 37.482861375
fmt.Println("Toplam:", total) // Toplam: 459.824961375
fmt.Println("Vergi oranı:", total.Sub(preTax).Div(preTax)) // Vergi oranı: 0.08875
}
4. Decimal Değişkenleri Oluşturma
Decimal kütüphanesi, Decimal değişkenleri oluşturmak için çeşitli yöntemler sunar. Desteklenen API'ler aşağıda verilmiştir:
-
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. Aritmetik İşlemler
Go Decimal kütüphanesi, Decimal değişkenleri üzerinde gerçekleştirilebilecek çeşitli aritmetik işlemler sunar. Desteklenen işlemler aşağıda verilmiştir:
-
Add(d2 Decimal) Decimal
: İki Decimal değeri ekler ve sonucu döndürür. -
Sub(d2 Decimal) Decimal
: Bir Decimal değerinden diğerini çıkarır ve sonucu döndürür. -
Div(d2 Decimal) Decimal
: Bir Decimal değerini diğerine böler ve sonucu döndürür. -
DivRound(d2 Decimal, precision int32) Decimal
: Bir Decimal değerini diğerine böler ve belirli bir hassasiyetle sonucu döndürür. -
Mod(d2 Decimal) Decimal
: Bir Decimal değerini başka bir Decimal değerine böldüğünde kalanı hesaplar ve sonucu döndürür. -
Mul(d2 Decimal) Decimal
: İki Decimal değerini çarpar ve sonucu döndürür.
Bu işlemleri kullanarak Decimal değerleri üzerinde yaygın aritmetik hesaplamaları yapabilirsiniz. Aşağıda bu işlemlerin kullanımını gösteren bir örnek bulunmaktadır:
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("Ara Toplam:", subtotal) // Ara Toplam: 408.06
fmt.Println("Vergi:", tax) // Vergi: 36.244985
fmt.Println("Toplam:", total) // Toplam: 444.304985
6. Yuvarlama İşlemleri
Go Decimal kütüphanesi, Decimal değerlerini belirli bir hassasiyete yuvarlamak için kullanılabilecek birkaç yuvarlama işlemi sağlar. İşte mevcut yuvarlama işlemlerinden bazıları:
-
Round(places int32) Decimal
: Decimal'i belirtilen ondalık basamağa yuvarlar. -
RoundBank(places int32) Decimal
: Decimal'i banker yuvarlamasını kullanarak belirtilen ondalık basamağa yuvarlar. -
RoundCash(interval uint8) Decimal
: Decimal'i 5 sent, 10 sent, 25 sent, 50 sent veya 1 dolar gibi belirli bir aralığa yuvarlar. -
RoundCeil(places int32) Decimal
: Decimal'i pozitif sonsuzluğa yuvarlar. -
RoundDown(places int32) Decimal
: Decimal'i sıfıra yuvarlar. -
RoundFloor(places int32) Decimal
: Decimal'i negatif sonsuzluğa yuvarlar. -
RoundUp(places int32) Decimal
: Decimal'i sıfırdan uzaklaştırarak yuvarlar.
6.1. Yuvarla
Yuvar, decimal'i belirtilen ondalık basamağa yuvarlar. Eğer places < 0 ise, tamsayı kısmını en yakın 10^(-places) değerine yuvarlar.
NewFromFloat(5.45).Round(1).String() // Çıktı: "5.5"
NewFromFloat(545).Round(-1).String() // Çıktı: "550"
6.2. RoundBank
RoundBank, decimal'i belirtilen ondalık basamağa yuvarlar. Eğer yuvarlanacak son rakam ile en yakın iki tamsayı arasındaki fark eşitse, yuvarlanmış değer çift sayı alır.
Eğer places < 0 ise, tamsayı kısmı en yakın 10^(-places) değerine yuvarlanır.
NewFromFloat(5.45).RoundBank(1).String() // Çıktı: "5.4"
NewFromFloat(545).RoundBank(-1).String() // Çıktı: "540"
NewFromFloat(5.46).RoundBank(1).String() // Çıktı: "5.5"
NewFromFloat(546).RoundBank(-1).String() // Çıktı: "550"
NewFromFloat(5.55).RoundBank(1).String() // Çıktı: "5.6"
NewFromFloat(555).RoundBank(-1).String() // Çıktı: "560"
6.3. RoundCash
RoundCash (aynı zamanda nakit/kuruş/İrlanda yuvarlaması olarak da bilinir), decimal'i belirli aralıklara yuvarlar. Nakit işlemi ödeme miktarı en küçük para birimi çarpanına yuvarlanır. Kullanılabilir aralıklar: 5, 10, 25, 50 ve 100; diğer herhangi bir sayı bir istisnaya neden olacaktır.
5: 5 cent yuvarlaması 3.43 => 3.45
10: 10 cent yuvarlaması 3.45 => 3.50 (5 yukarı yuvarlanır)
25: 25 cent yuvarlaması 3.41 => 3.50
50: 50 cent yuvarlaması 3.75 => 4.00
100: 100 cent yuvarlaması 3.50 => 4.00
6.4. RoundCeil
RoundCeil, decimal'i pozitif sonsuzluğa yuvarlar.
NewFromFloat(545).RoundCeil(-2).String() // Çıktı: "600"
NewFromFloat(500).RoundCeil(-2).String() // Çıktı: "500"
NewFromFloat(1.1001).RoundCeil(2).String() // Çıktı: "1.11"
NewFromFloat(-1.454).RoundCeil(1).String() // Çıktı: "-1.5"
6.5. RoundDown
RoundDown, decimal'i sıfıra yuvarlar.
NewFromFloat(545).RoundDown(-2).String() // Çıktı: "500"
NewFromFloat(-500).RoundDown(-2).String() // Çıktı: "-500"
NewFromFloat(1.1001).RoundDown(2).String() // Çıktı: "1.1"
NewFromFloat(-1.454).RoundDown(1).String() // Çıktı: "-1.5"
6.6. RoundFloor
RoundFloor, ondalık sayıyı negatif sonsuza doğru yuvarlar.
NewFromFloat(545).RoundFloor(-2).String() // Çıktı: "500"
NewFromFloat(-500).RoundFloor(-2).String() // Çıktı: "-500"
NewFromFloat(1.1001).RoundFloor(2).String() // Çıktı: "1.1"
NewFromFloat(-1.454).RoundFloor(1).String() // Çıktı: "-1.4"
6.7. RoundUp
RoundUp, ondalık sayıyı sıfırdan uzakta yukarıya doğru yuvarlar.
NewFromFloat(545).RoundUp(-2).String() // Çıktı: "600"
NewFromFloat(500).RoundUp(-2).String() // Çıktı: "500"
NewFromFloat(1.1001).RoundUp(2).String() // Çıktı: "1.11"
NewFromFloat(-1.454).RoundUp(1).String() // Çıktı: "-1.4"
7. Decimal Türünü String'e Dönüştürme
Go Decimal kütüphanesi, Decimal değerlerini string temsillere dönüştürmek için yöntemler sağlar. İşte bazı mevcut yöntemler:
-
String(): string
: Ondalık sayının sabit ondalık noktasıyla string temsili döndürür. -
StringFixed(places int32) string
: Belirtilen ondalık basamak sayısıyla yuvarlanmış string temsilini döndürür. -
StringFixedBank(places int32) string
: Belirtilen ondalık basamak sayısıyla yuvarlanmış (banker's rounding) string temsilini döndürür.
Ihtiyacınıza göre uygun yöntemi seçebilirsiniz. Aşağıda bir ondalık sayının string'e dönüştürülmesi örneği bulunmaktadır:
d := decimal.NewFromFloat(5.45)
str := d.String()
fmt.Println("Ondalık sayının string temsili:", str) // Ondalık sayının string temsili: 5.45
// StringFixed Örneği
NewFromFloat(0).StringFixed(2) // Çıktı: "0.00"
NewFromFloat(0).StringFixed(0) // Çıktı: "0"
NewFromFloat(5.45).StringFixed(0) // Çıktı: "5"
NewFromFloat(5.45).StringFixed(1) // Çıktı: "5.5"
NewFromFloat(5.45).StringFixed(2) // Çıktı: "5.45"
NewFromFloat(5.45).StringFixed(3) // Çıktı: "5.450"
NewFromFloat(545).StringFixed(-1) // Çıktı: "550"
// StringFixedBank Örneği
NewFromFloat(0).StringFixedBank(2) // Çıktı: "0.00"
NewFromFloat(0).StringFixedBank(0) // Çıktı: "0"
NewFromFloat(5.45).StringFixedBank(0) // Çıktı: "5"
NewFromFloat(5.45).StringFixedBank(1) // Çıktı: "5.4"
NewFromFloat(5.45).StringFixedBank(2) // Çıktı: "5.45"
NewFromFloat(5.45).StringFixedBank(3) // Çıktı: "5.450"
NewFromFloat(545).StringFixedBank(-1) // Çıktı: "540"
8. Yaygın Sorular
S: Neden doğrudan float64 kullanılmıyor? C: float64, 0.1 gibi sayıları doğru bir şekilde temsil edemez, bu da küçük hatalara yol açabilir. Finansal hesaplamalar içeren durumlarda, bu hatalar zamanla birikebilir ve önemli sorunlara yol açabilir.
S: Neden big.Rat doğrudan kullanılmıyor? C: big.Rat rasyonel sayıları temsil edebilirken, para birimini temsil etmek için uygun değildir. Ondalık sayılar, hassasiyeti kaybetmeden ondalık kesirleri doğru bir şekilde temsil edebildikleri için finansal hesaplamalar için daha iyidir.
S: API neden big.Int'e benzer değil? C: Decimal kütüphanesinin API'si, performans yerine kullanılabilirlik ve doğruluk önceliğine sahiptir. big.Int'in API'si, performans nedenleriyle bellek atamalarını azaltırken, karmaşık ve hatalı kodlara yol açabilir. Decimal kütüphanesinin API'si basit ve anlaşılması kolay olacak şekilde tasarlanmıştır.