1. Introduzione
La libreria Go Decimal è uno strumento potente per gestire decimali a virgola fissa a precisione arbitraria nel linguaggio Go. Consente di eseguire operazioni di addizione, sottrazione, moltiplicazione e divisione senza perdere precisione. Inoltre, fornisce funzionalità come la serializzazione/deserializzazione del database/SQL, nonché la serializzazione/deserializzazione JSON/XML.
2. Installazione
Per installare la libreria Go Decimal, è possibile utilizzare il seguente comando:
go get github.com/shopspring/decimal
Si prega di notare che la libreria Decimal richiede Go versione >=1.7.
3. Utilizzo di base
Per utilizzare la libreria Decimal in un programma Go, importa il pacchetto "github.com/shopspring/decimal". Ecco un semplice esempio di codice che dimostra l'utilizzo di base:
package main
import (
"fmt"
"github.com/shopspring/decimal"
)
func main() {
prezzo, err := decimal.NewFromString("136.02")
if err != nil {
panic(err)
}
quantità := decimal.NewFromInt(3)
commissione, _ := decimal.NewFromString(".035")
tariffaTasse, _ := decimal.NewFromString(".08875")
subtotale := prezzo.Mul(quantità)
preTasse := subtotale.Mul(commissione).Add(decimal.NewFromFloat(1))
totale := preTasse.Mul(tariffaTasse).Add(decimal.NewFromFloat(1))
fmt.Println("Subtotale:", subtotale) // Subtotale: 408.06
fmt.Println("Pre-tasse:", preTasse) // Pre-tasse: 422.3421
fmt.Println("Tasse:", totale.Sub(preTasse)) // Tasse: 37.482861375
fmt.Println("Totale:", totale) // Totale: 459.824961375
fmt.Println("Tariffa tasse:", totale.Sub(preTasse).Div(preTasse)) // Tariffa tasse: 0.08875
}
4. Creazione di variabili Decimal
La libreria Decimal fornisce vari metodi per creare variabili Decimal. Di seguito sono riportate le API supportate:
-
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. Operazioni aritmetiche
La libreria Go Decimal fornisce diverse operazioni aritmetiche che possono essere eseguite su variabili Decimal. Ecco alcune operazioni supportate:
-
Add(d2 Decimal) Decimal
: Aggiunge due valori Decimal restituendo il risultato. -
Sub(d2 Decimal) Decimal
: Sottrae un valore Decimal da un altro e restituisce il risultato. -
Div(d2 Decimal) Decimal
: Divide un valore Decimal per un altro e restituisce il risultato. -
DivRound(d2 Decimal, precision int32) Decimal
: Divide un valore Decimal per un altro e restituisce il risultato con la precisione specificata. -
Mod(d2 Decimal) Decimal
: Calcola il modulo (resto) di un valore Decimal diviso per un altro e restituisce il risultato. -
Mul(d2 Decimal) Decimal
: Moltiplica due valori Decimal e restituisce il risultato.
È possibile utilizzare queste operazioni per eseguire calcoli aritmetici comuni su valori Decimal. Ecco un esempio che dimostra l'utilizzo di queste operazioni:
prezzo, _ := decimal.NewFromString("136.02")
quantità := decimal.NewFromInt(3)
subtotale := prezzo.Mul(quantità)
tasse := subtotale.Mul(decimal.NewFromFloat(0.08875))
totale := subtotale.Add(tasse)
fmt.Println("Subtotale:", subtotale) // Subtotale: 408.06
fmt.Println("Tasse:", tasse) // Tasse: 36.244985
fmt.Println("Totale:", totale) // Totale: 444.304985
Nell'esempio precedente, utilizziamo il metodo Mul()
per calcolare il subtotale
moltiplicando prezzo
e quantità
. Quindi calcoliamo le tasse
moltiplicando subtotale
per il tasso fiscale. Infine, calcoliamo il totale
aggiungendo subtotale
e tasse
utilizzando il metodo Add()
.
6. Operazioni di Arrotondamento
La libreria Decimal di Go fornisce diverse operazioni di arrotondamento che possono essere utilizzate per arrotondare i valori Decimal a una precisione specifica. Ecco alcune operazioni di arrotondamento disponibili:
-
Round(places int32) Decimal
: Arrotonda il decimale al numero specificato di cifre decimali. -
RoundBank(places int32) Decimal
: Arrotonda il decimale utilizzando l'arrotondamento bancario al numero specificato di cifre decimali. -
RoundCash(interval uint8) Decimal
: Arrotonda il decimale a un intervallo specifico, come 5 centesimi, 10 centesimi, 25 centesimi, 50 centesimi o 1 dollaro. -
RoundCeil(places int32) Decimal
: Arrotonda il decimale verso l'infinito positivo. -
RoundDown(places int32) Decimal
: Arrotonda il decimale verso lo zero. -
RoundFloor(places int32) Decimal
: Arrotonda il decimale verso l'infinito negativo. -
RoundUp(places int32) Decimal
: Arrotonda il decimale lontano dallo zero.
6.1. Round
Round arrotonda il decimale al numero specificato di cifre decimali. Se places < 0, arrotonda la parte intera al 10^(-places) più vicino.
NewFromFloat(5.45).Round(1).String() // Output: "5.5"
NewFromFloat(545).Round(-1).String() // Output: "550"
6.2. RoundBank
RoundBank arrotonda il decimale a places cifre decimali. Se la distanza tra l'ultima cifra da arrotondare e i due interi più vicini è uguale, il valore arrotondato prende il numero pari.
Se places < 0, la parte intera verrà arrotondata al 10^(-places) più vicino.
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 (noto anche come arrotondamento cash/penny/irlandese) arrotonda il decimale a intervalli specifici. L'importo pagabile di una transazione in contanti verrà arrotondato al multiplo più vicino dell'unità monetaria più piccola. Gli intervalli disponibili sono: 5, 10, 25, 50 e 100; qualsiasi altro numero causerà un'eccezione.
5: arrotondamento a 5 centesimi 3.43 => 3.45
10: arrotondamento a 10 centesimi 3.45 => 3.50 (5 viene arrotondato per eccesso)
25: arrotondamento a 25 centesimi 3.41 => 3.50
50: arrotondamento a 50 centesimi 3.75 => 4.00
100: arrotondamento a 100 centesimi 3.50 => 4.00
6.4. RoundCeil
RoundCeil arrotonda il decimale verso l'infinito positivo.
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 arrotonda il decimale verso lo zero.
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 arrotonda il decimale verso meno infinito.
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 arrotonda il decimale lontano da zero.
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. Convertire il Tipo Decimal in Stringa
La libreria Decimal di Go fornisce metodi per convertire i valori Decimal in rappresentazioni stringa. Ecco alcuni metodi disponibili:
-
String(): string
: Restituisce la rappresentazione stringa del numero decimale con un punto decimale fisso. -
StringFixed(places int32) string
: Restituisce la rappresentazione stringa arrotondata con un numero specificato di posizioni decimali. -
StringFixedBank(places int32) string
: Restituisce la rappresentazione stringa arrotondata (arrotondamento bancario) con un numero specificato di posizioni decimali.
Puoi scegliere il metodo appropriato in base alle tue esigenze. Di seguito è riportato un esempio di conversione di un numero decimale in una stringa:
d := decimal.NewFromFloat(5.45)
str := d.String()
fmt.Println("Rappresentazione stringa del numero decimale:", str) // Rappresentazione stringa del numero decimale: 5.45
// Esempio di 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"
// Esempio di 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. Domande Comuni
Q: Perché non usare direttamente float64? A: float64 non può rappresentare con precisione numeri come 0.1, il che può causare piccoli errori. In situazioni che coinvolgono calcoli finanziari, questi errori possono accumularsi nel tempo e causare problemi significativi.
Q: Perché non usare direttamente big.Rat? A: Anche se big.Rat può rappresentare numeri razionali, non è adatto per rappresentare valute. I numeri decimali sono migliori per calcoli finanziari in quanto possono rappresentare con precisione frazioni decimali senza perdere precisione.
Q: Perché l'API non è simile a big.Int? A: L'API della libreria Decimal dà priorità all'usabilità e alla correttezza rispetto alle prestazioni. Mentre l'API di big.Int riduce le assegnazioni di memoria per motivi di prestazioni, potrebbe portare a codice complesso e soggetto a errori. L'API della libreria Decimal è progettata per essere semplice e di facile comprensione.