# background

Recently, while writing go, I encountered a problem that GO has no built-in Decimal type and only a math/ BIG for large number operations. In the case of shopping payments, it is necessary to use floating-point calculations, usually to two decimal places.

After consulting some information, I found a solution with a relatively high start number.

Note that the Decimal library “can only” represent numbers up to 2^31 Decimal places. But it’s enough to meet our current needs.

The idea is to use fixed-point decimal notation, where you move the decimal number back as many decimal places as you have, value holds the number of decimal places, exp holds the number of decimal places, number=value*10^exp, because the decimal number can be very large, So I’m borrowing the standard package math/big for this big integer. Exp uses int32, which is why the Decimal library “can only” represent numbers up to 2^31 Decimal places.

Here is the definition of Decimal in the source code

``````type Decimal struct {
value *big.Int

// NOTE(vadim): this must be an int32, because we cast it to float64 during
// calculations. If exp is 64 bit, we might lose precision.
// If we cared about being able to represent every possible decimal, we
// could make exp a *big.Int but it would hurt performance and numbers
// like that are unrealistic.
exp int32
}
Copy the code``````

# The sample

Prerequisites: Go version >=1.7

``````go get github.com/shopspring/decimal
Copy the code``````
``````package main

import (
"fmt"
"github.com/shopspring/decimal"
)

func main(a) {
// Convert string to Decimal
price, err := decimal.NewFromString("136.02")
iferr ! =nil {
panic(err)
}

// Negative numbers are supported
n, err := decimal.NewFromString("123.4567")
n.String() / / the output: "123.4567"

// Convert int to Decimal
quantity := decimal.NewFromInt(3)

// If the integer department is empty, it can be converted normally
fee, _ := decimal.NewFromString("035")
taxRate, _ := decimal.NewFromString("08875")
/ / by
subtotal := price.Mul(quantity)
// First add and then multiply

fmt.Println("Subtotal:", subtotal)                      / / Subtotal: 408.06
fmt.Println("Pre-tax:", preTax)                         / / the 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

// Support scientific enumeration
fmt.Println(NewFromFloat(-1e13).String()) // output: "-10000000000000"

By default, there is no exact number of digits after the decimal point
d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
d1.String() / / the output: "0.6666666666666667"

// Keep three decimal places
decimal.DivisionPrecision = 3
d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
d4.String() / / the output: "0.667"
}
Copy the code``````