1. Wprowadzenie
Biblioteka Decimal w języku Go jest potężnym narzędziem do obsługi liczb dziesiętnych o dowolnej precyzji w języku Go. Umożliwia dodawanie, odejmowanie, mnożenie i dzielenie operacji bez utraty precyzji. Dodatkowo zapewnia funkcje takie jak serializacja/deserializacja bazy danych/SQL, jak również serializacja/deserializacja JSON/XML.
2. Instalacja
Aby zainstalować bibliotekę Decimal w języku Go, można użyć poniższej komendy:
go get github.com/shopspring/decimal
Należy pamiętać, że biblioteka Decimal wymaga wersji Go >=1.7.
3. Podstawowe użycie
Aby użyć biblioteki Decimal w programie Go, zaimportuj pakiet "github.com/shopspring/decimal". Poniżej przedstawiono prosty przykładowy kod demonstrujący podstawowe użycie:
pakiet główny
import (
"fmt"
"github.com/shopspring/decimal"
)
funkcja główna() {
cena, błąd := decimal.NewFromString("136.02")
jeśli błąd != nil {
panic(błąd)
}
ilość := decimal.NewFromInt(3)
opłata, _ := decimal.NewFromString(".035")
stawkaPodatku, _ := decimal.NewFromString(".08875")
sumaCzęściowa := cena.Mul(ilość)
przedPodatkiem := sumaCzęściowa.Mul(opłata).Add(decimal.NewFromFloat(1))
całkowita := przedPodatkiem.Mul(stawkaPodatku).Add(decimal.NewFromFloat(1))
fmt.Println("Suma częściowa:", sumaCzęściowa) // Suma częściowa: 408.06
fmt.Println("Przed opodatkowaniem:", przedPodatkiem) // Przed opodatkowaniem: 422.3421
fmt.Println("Podatki:", całkowita.Sub(przedPodatkiem)) // Podatki: 37.482861375
fmt.Println("Całkowita:", całkowita) // Całkowita: 459.824961375
fmt.Println("Stawka podatkowa:", całkowita.Sub(przedPodatkiem).Div(przedPodatkiem)) // Stawka podatkowa: 0.08875
}
4. Tworzenie zmiennych Decimal
Biblioteka Decimal udostępnia różne metody tworzenia zmiennych Decimal. Oto obsługiwane interfejsy API:
-
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. Operacje arytmetyczne
Biblioteka Decimal w języku Go udostępnia kilka operacji arytmetycznych, które można wykonać na zmiennych Decimal. Oto obsługiwane operacje:
-
Add(d2 Decimal) Decimal
: Dodaje dwie wartości Decimal i zwraca wynik. -
Sub(d2 Decimal) Decimal
: Odejmuje jedną wartość Decimal od drugiej i zwraca wynik. -
Div(d2 Decimal) Decimal
: Dzieli jedną wartość Decimal przez inną i zwraca wynik. -
DivRound(d2 Decimal, precision int32) Decimal
: Dzieli jedną wartość Decimal przez inną i zwraca wynik z określoną precyzją. -
Mod(d2 Decimal) Decimal
: Oblicza resztę z dzielenia jednej wartości Decimal przez inną i zwraca wynik. -
Mul(d2 Decimal) Decimal
: Mnoży dwie wartości Decimal i zwraca wynik.
Można użyć tych operacji do wykonywania standardowych obliczeń arytmetycznych na wartościach Decimal. Poniżej przedstawiono przykład wykorzystania tych operacji:
cena, _ := decimal.NewFromString("136.02")
ilość := decimal.NewFromInt(3)
sumaCzęściowa := cena.Mul(ilość)
podatek := sumaCzęściowa.Mul(decimal.NewFromFloat(0.08875))
całkowita := sumaCzęściowa.Add(podatek)
fmt.Println("Suma częściowa:", sumaCzęściowa) // Suma częściowa: 408.06
fmt.Println("Podatek:", podatek) // Podatek: 36.244985
fmt.Println("Całkowita:", całkowita) // Całkowita: 444.304985
W powyższym przykładzie używamy metody Mul()
do obliczenia sumaCzęściowa
poprzez pomnożenie cena
i ilość
. Następnie obliczamy podatek
poprzez pomnożenie sumaCzęściowa
przez stawkę podatku. Na końcu obliczamy całkowita
poprzez dodanie sumaCzęściowa
i podatek
za pomocą metody Add()
.
6. Operacje zaokrąglania
Biblioteka Go Decimal zapewnia kilka operacji zaokrąglania, które można użyć do zaokrąglania wartości Decimal do określonej precyzji. Oto kilka dostępnych operacji zaokrąglania:
-
Round(places int32) Decimal
: Zaokrągla wartość dziesiętną do określonej liczby miejsc po przecinku. -
RoundBank(places int32) Decimal
: Zaokrągla wartość dziesiętną zgodnie z zaokrąglaniem bankowym do określonej liczby miejsc po przecinku. -
RoundCash(interval uint8) Decimal
: Zaokrągla wartość dziesiętną do określonego interwału, takiego jak 5 centów, 10 centów, 25 centów, 50 centów lub 1 dolara. -
RoundCeil(places int32) Decimal
: Zaokrągla wartość dziesiętną w kierunku dodatniej nieskończoności. -
RoundDown(places int32) Decimal
: Zaokrągla wartość dziesiętną w kierunku zera. -
RoundFloor(places int32) Decimal
: Zaokrągla wartość dziesiętną w kierunku ujemnej nieskończoności. -
RoundUp(places int32) Decimal
: Zaokrągla wartość dziesiętną w kierunku od zera.
6.1. Round
Round zaokrągla wartość dziesiętną do określonej liczby miejsc po przecinku. Jeśli places < 0, zaokrągla część całkowitą do najbliższej 10^(-places).
NewFromFloat(5.45).Round(1).String() // Output: "5.5"
NewFromFloat(545).Round(-1).String() // Output: "550"
6.2. RoundBank
RoundBank zaokrągla wartość dziesiętną do miejsc po przecinku. Jeśli odległość między ostatnią cyfrą do zaokrąglenia a najbliższymi dwoma liczbami całkowitymi jest równa, zaokrąglona wartość przyjmuje parzystą liczbę.
Jeśli places < 0, część całkowita zostanie zaokrąglona do najbliższej 10^(-places).
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 (znane również jako zaokrąglanie gotówkowe/monet/polskie) zaokrągla wartość dziesiętną do konkretnych interwałów. Kwota płatna w transakcji gotówkowej zostanie zaokrąglona do najbliższej wielokrotności najmniejszej jednostki waluty. Dostępne interwały to: 5, 10, 25, 50 i 100; jakakolwiek inna liczba spowoduje wyjątek.
5: Zaokrąglanie do 5 centów 3.43 => 3.45
10: Zaokrąglanie do 10 centów 3.45 => 3.50 (5 jest zaokrąglane w górę)
25: Zaokrąglanie do 25 centów 3.41 => 3.50
50: Zaokrąglanie do 50 centów 3.75 => 4.00
100: Zaokrąglanie do 100 centów 3.50 => 4.00
6.4. RoundCeil
RoundCeil zaokrągla wartość dziesiętną w kierunku dodatniej nieskończoności.
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 zaokrągla wartość dziesiętną w kierunku zera.
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 zaokrągla liczbę zmiennoprzecinkową w kierunku ujemnej nieskończoności.
NewFromFloat(545).RoundFloor(-2).String() // Wynik: "500"
NewFromFloat(-500).RoundFloor(-2).String() // Wynik: "-500"
NewFromFloat(1.1001).RoundFloor(2).String() // Wynik: "1.1"
NewFromFloat(-1.454).RoundFloor(1).String() // Wynik: "-1.4"
6.7. RoundUp
RoundUp zaokrągla liczbę zmiennoprzecinkową w kierunku od zera.
NewFromFloat(545).RoundUp(-2).String() // Wynik: "600"
NewFromFloat(500).RoundUp(-2).String() // Wynik: "500"
NewFromFloat(1.1001).RoundUp(2).String() // Wynik: "1.11"
NewFromFloat(-1.454).RoundUp(1).String() // Wynik: "-1.4"
7. Konwertowanie typu Decimal do stringa
Biblioteka Go Decimal udostępnia metody do konwertowania wartości Decimal na reprezentacje stringa. Oto kilka dostępnych metod:
-
String(): string
: Zwraca reprezentację stringową liczby dziesiętnej z ustalonym miejscem dziesiętnym. -
StringFixed(places int32) string
: Zwraca zaokrągloną reprezentację stringową z określoną liczbą miejsc dziesiętnych. -
StringFixedBank(places int32) string
: Zwraca zaokrągloną (zaokrąglanie do najbliższej parzystej) reprezentację stringową z określoną liczbą miejsc dziesiętnych.
Możesz wybrać odpowiednią metodę zgodnie z Twoimi potrzebami. Poniżej znajduje się przykład konwertowania liczby dziesiętnej na stringa:
d := decimal.NewFromFloat(5.45)
str := d.String()
fmt.Println("Reprezentacja stringowa liczby dziesiętnej:", str) // Reprezentacja stringowa liczby dziesiętnej: 5.45
// Przykład użycia StringFixed
NewFromFloat(0).StringFixed(2) // Wynik: "0.00"
NewFromFloat(0).StringFixed(0) // Wynik: "0"
NewFromFloat(5.45).StringFixed(0) // Wynik: "5"
NewFromFloat(5.45).StringFixed(1) // Wynik: "5.5"
NewFromFloat(5.45).StringFixed(2) // Wynik: "5.45"
NewFromFloat(5.45).StringFixed(3) // Wynik: "5.450"
NewFromFloat(545).StringFixed(-1) // Wynik: "550"
// Przykład użycia StringFixedBank
NewFromFloat(0).StringFixedBank(2) // Wynik: "0.00"
NewFromFloat(0).StringFixedBank(0) // Wynik: "0"
NewFromFloat(5.45).StringFixedBank(0) // Wynik: "5"
NewFromFloat(5.45).StringFixedBank(1) // Wynik: "5.4"
NewFromFloat(5.45).StringFixedBank(2) // Wynik: "5.45"
NewFromFloat(5.45).StringFixedBank(3) // Wynik: "5.450"
NewFromFloat(545).StringFixedBank(-1) // Wynik: "540"
8. Często zadawane pytania
Q: Dlaczego nie używać bezpośrednio float64? A: float64 nie może dokładnie reprezentować liczb takich jak 0.1, co może prowadzić do małych błędów. W sytuacjach związanych z obliczeniami finansowymi te błędy mogą gromadzić się w czasie i powodować poważne problemy.
Q: Dlaczego nie używać bezpośrednio big.Rat? A: Chociaż big.Rat może reprezentować liczby wymierne, nie nadaje się do reprezentowania waluty. Liczby dziesiętne są lepsze do obliczeń finansowych, ponieważ mogą dokładnie reprezentować ułamki dziesiętne bez utraty precyzji.
Q: Dlaczego API nie jest podobne do big.Int? A: API biblioteki Decimal stawia na użyteczność i poprawność kosztem wydajności. Podczas gdy API big.Int redukuje alokacje pamięci ze względu na wydajność, może to prowadzić do złożonego i podatnego na błędy kodu. API biblioteki Decimal zostało zaprojektowane tak, aby było proste i łatwe do zrozumienia.