mirror of
https://github.com/shopspring/decimal.git
synced 2024-11-22 20:40:48 +01:00
feat: unmarshal empty string as zero
This commit is contained in:
parent
f55dd56454
commit
4f0d5886aa
2 changed files with 122 additions and 120 deletions
225
decimal.go
225
decimal.go
|
@ -4,14 +4,14 @@
|
||||||
//
|
//
|
||||||
// The best way to create a new Decimal is to use decimal.NewFromString, ex:
|
// The best way to create a new Decimal is to use decimal.NewFromString, ex:
|
||||||
//
|
//
|
||||||
// n, err := decimal.NewFromString("-123.4567")
|
// n, err := decimal.NewFromString("-123.4567")
|
||||||
// n.String() // output: "-123.4567"
|
// n.String() // output: "-123.4567"
|
||||||
//
|
//
|
||||||
// To use Decimal as part of a struct:
|
// To use Decimal as part of a struct:
|
||||||
//
|
//
|
||||||
// type Struct struct {
|
// type Struct struct {
|
||||||
// Number Decimal
|
// Number Decimal
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Note: This can "only" represent numbers with a maximum of 2^31 digits after the decimal point.
|
// Note: This can "only" represent numbers with a maximum of 2^31 digits after the decimal point.
|
||||||
package decimal
|
package decimal
|
||||||
|
@ -32,16 +32,15 @@ import (
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
|
// d1 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
|
||||||
// d1.String() // output: "0.6666666666666667"
|
// d1.String() // output: "0.6666666666666667"
|
||||||
// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000))
|
// d2 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(30000))
|
||||||
// d2.String() // output: "0.0000666666666667"
|
// d2.String() // output: "0.0000666666666667"
|
||||||
// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3))
|
// d3 := decimal.NewFromFloat(20000).Div(decimal.NewFromFloat(3))
|
||||||
// d3.String() // output: "6666.6666666666666667"
|
// d3.String() // output: "6666.6666666666666667"
|
||||||
// decimal.DivisionPrecision = 3
|
// decimal.DivisionPrecision = 3
|
||||||
// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
|
// d4 := decimal.NewFromFloat(2).Div(decimal.NewFromFloat(3))
|
||||||
// d4.String() // output: "0.667"
|
// d4.String() // output: "0.667"
|
||||||
//
|
|
||||||
var DivisionPrecision = 16
|
var DivisionPrecision = 16
|
||||||
|
|
||||||
// MarshalJSONWithoutQuotes should be set to true if you want the decimal to
|
// MarshalJSONWithoutQuotes should be set to true if you want the decimal to
|
||||||
|
@ -95,8 +94,8 @@ func New(value int64, exp int32) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromInt(123).String() // output: "123"
|
// NewFromInt(123).String() // output: "123"
|
||||||
// NewFromInt(-10).String() // output: "-10"
|
// NewFromInt(-10).String() // output: "-10"
|
||||||
func NewFromInt(value int64) Decimal {
|
func NewFromInt(value int64) Decimal {
|
||||||
return Decimal{
|
return Decimal{
|
||||||
value: big.NewInt(value),
|
value: big.NewInt(value),
|
||||||
|
@ -108,8 +107,8 @@ func NewFromInt(value int64) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromInt(123).String() // output: "123"
|
// NewFromInt(123).String() // output: "123"
|
||||||
// NewFromInt(-10).String() // output: "-10"
|
// NewFromInt(-10).String() // output: "-10"
|
||||||
func NewFromInt32(value int32) Decimal {
|
func NewFromInt32(value int32) Decimal {
|
||||||
return Decimal{
|
return Decimal{
|
||||||
value: big.NewInt(int64(value)),
|
value: big.NewInt(int64(value)),
|
||||||
|
@ -130,10 +129,9 @@ func NewFromBigInt(value *big.Int, exp int32) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// d, err := NewFromString("-123.45")
|
// d, err := NewFromString("-123.45")
|
||||||
// d2, err := NewFromString(".0001")
|
// d2, err := NewFromString(".0001")
|
||||||
// d3, err := NewFromString("1.47000")
|
// d3, err := NewFromString("1.47000")
|
||||||
//
|
|
||||||
func NewFromString(value string) (Decimal, error) {
|
func NewFromString(value string) (Decimal, error) {
|
||||||
originalInput := value
|
originalInput := value
|
||||||
var intString string
|
var intString string
|
||||||
|
@ -211,15 +209,14 @@ func NewFromString(value string) (Decimal, error) {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// r := regexp.MustCompile("[$,]")
|
// r := regexp.MustCompile("[$,]")
|
||||||
// d1, err := NewFromFormattedString("$5,125.99", r)
|
// d1, err := NewFromFormattedString("$5,125.99", r)
|
||||||
//
|
//
|
||||||
// r2 := regexp.MustCompile("[_]")
|
// r2 := regexp.MustCompile("[_]")
|
||||||
// d2, err := NewFromFormattedString("1_000_000", r2)
|
// d2, err := NewFromFormattedString("1_000_000", r2)
|
||||||
//
|
|
||||||
// r3 := regexp.MustCompile("[USD\\s]")
|
|
||||||
// d3, err := NewFromFormattedString("5000 USD", r3)
|
|
||||||
//
|
//
|
||||||
|
// r3 := regexp.MustCompile("[USD\\s]")
|
||||||
|
// d3, err := NewFromFormattedString("5000 USD", r3)
|
||||||
func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) {
|
func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, error) {
|
||||||
parsedValue := replRegexp.ReplaceAllString(value, "")
|
parsedValue := replRegexp.ReplaceAllString(value, "")
|
||||||
d, err := NewFromString(parsedValue)
|
d, err := NewFromString(parsedValue)
|
||||||
|
@ -234,9 +231,8 @@ func NewFromFormattedString(value string, replRegexp *regexp.Regexp) (Decimal, e
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// d := RequireFromString("-123.45")
|
// d := RequireFromString("-123.45")
|
||||||
// d2 := RequireFromString(".0001")
|
// d2 := RequireFromString(".0001")
|
||||||
//
|
|
||||||
func RequireFromString(value string) Decimal {
|
func RequireFromString(value string) Decimal {
|
||||||
dec, err := NewFromString(value)
|
dec, err := NewFromString(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -332,8 +328,7 @@ func newFromFloat(val float64, bits uint64, flt *floatInfo) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46"
|
// NewFromFloatWithExponent(123.456, -2).String() // output: "123.46"
|
||||||
//
|
|
||||||
func NewFromFloatWithExponent(value float64, exp int32) Decimal {
|
func NewFromFloatWithExponent(value float64, exp int32) Decimal {
|
||||||
if math.IsNaN(value) || math.IsInf(value, 0) {
|
if math.IsNaN(value) || math.IsInf(value, 0) {
|
||||||
panic(fmt.Sprintf("Cannot create a Decimal from %v", value))
|
panic(fmt.Sprintf("Cannot create a Decimal from %v", value))
|
||||||
|
@ -430,7 +425,7 @@ func (d Decimal) Copy() Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// d := New(12345, -4)
|
// d := New(12345, -4)
|
||||||
// d2 := d.rescale(-1)
|
// d2 := d.rescale(-1)
|
||||||
// d3 := d2.rescale(-4)
|
// d3 := d2.rescale(-4)
|
||||||
// println(d1)
|
// println(d1)
|
||||||
|
@ -442,7 +437,6 @@ func (d Decimal) Copy() Decimal {
|
||||||
// 1.2345
|
// 1.2345
|
||||||
// 1.2
|
// 1.2
|
||||||
// 1.2000
|
// 1.2000
|
||||||
//
|
|
||||||
func (d Decimal) rescale(exp int32) Decimal {
|
func (d Decimal) rescale(exp int32) Decimal {
|
||||||
d.ensureInitialized()
|
d.ensureInitialized()
|
||||||
|
|
||||||
|
@ -554,9 +548,11 @@ func (d Decimal) Div(d2 Decimal) Decimal {
|
||||||
|
|
||||||
// QuoRem does division with remainder
|
// QuoRem does division with remainder
|
||||||
// d.QuoRem(d2,precision) returns quotient q and remainder r such that
|
// d.QuoRem(d2,precision) returns quotient q and remainder r such that
|
||||||
// d = d2 * q + r, q an integer multiple of 10^(-precision)
|
//
|
||||||
// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0
|
// d = d2 * q + r, q an integer multiple of 10^(-precision)
|
||||||
// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0
|
// 0 <= r < abs(d2) * 10 ^(-precision) if d>=0
|
||||||
|
// 0 >= r > -abs(d2) * 10 ^(-precision) if d<0
|
||||||
|
//
|
||||||
// Note that precision<0 is allowed as input.
|
// Note that precision<0 is allowed as input.
|
||||||
func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) {
|
func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) {
|
||||||
d.ensureInitialized()
|
d.ensureInitialized()
|
||||||
|
@ -599,8 +595,10 @@ func (d Decimal) QuoRem(d2 Decimal, precision int32) (Decimal, Decimal) {
|
||||||
|
|
||||||
// DivRound divides and rounds to a given precision
|
// DivRound divides and rounds to a given precision
|
||||||
// i.e. to an integer multiple of 10^(-precision)
|
// i.e. to an integer multiple of 10^(-precision)
|
||||||
// for a positive quotient digit 5 is rounded up, away from 0
|
//
|
||||||
// if the quotient is negative then digit 5 is rounded down, away from 0
|
// for a positive quotient digit 5 is rounded up, away from 0
|
||||||
|
// if the quotient is negative then digit 5 is rounded down, away from 0
|
||||||
|
//
|
||||||
// Note that precision<0 is allowed as input.
|
// Note that precision<0 is allowed as input.
|
||||||
func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal {
|
func (d Decimal) DivRound(d2 Decimal, precision int32) Decimal {
|
||||||
// QuoRem already checks initialization
|
// QuoRem already checks initialization
|
||||||
|
@ -655,9 +653,8 @@ func (d Decimal) Pow(d2 Decimal) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000"
|
// NewFromFloat(26.1).ExpHullAbrham(2).String() // output: "220000000000"
|
||||||
// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284"
|
// NewFromFloat(26.1).ExpHullAbrham(20).String() // output: "216314672147.05767284"
|
||||||
//
|
|
||||||
func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) {
|
func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) {
|
||||||
// Algorithm based on Variable precision exponential function.
|
// Algorithm based on Variable precision exponential function.
|
||||||
// ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham.
|
// ACM Transactions on Mathematical Software by T. E. Hull & A. Abrham.
|
||||||
|
@ -747,15 +744,14 @@ func (d Decimal) ExpHullAbrham(overallPrecision uint32) (Decimal, error) {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// d, err := NewFromFloat(26.1).ExpTaylor(2).String()
|
// d, err := NewFromFloat(26.1).ExpTaylor(2).String()
|
||||||
// d.String() // output: "216314672147.06"
|
// d.String() // output: "216314672147.06"
|
||||||
//
|
//
|
||||||
// NewFromFloat(26.1).ExpTaylor(20).String()
|
// NewFromFloat(26.1).ExpTaylor(20).String()
|
||||||
// d.String() // output: "216314672147.05767284062928674083"
|
// d.String() // output: "216314672147.05767284062928674083"
|
||||||
//
|
|
||||||
// NewFromFloat(26.1).ExpTaylor(-10).String()
|
|
||||||
// d.String() // output: "220000000000"
|
|
||||||
//
|
//
|
||||||
|
// NewFromFloat(26.1).ExpTaylor(-10).String()
|
||||||
|
// d.String() // output: "220000000000"
|
||||||
func (d Decimal) ExpTaylor(precision int32) (Decimal, error) {
|
func (d Decimal) ExpTaylor(precision int32) (Decimal, error) {
|
||||||
// Note(mwoss): Implementation can be optimized by exclusively using big.Int API only
|
// Note(mwoss): Implementation can be optimized by exclusively using big.Int API only
|
||||||
if d.IsZero() {
|
if d.IsZero() {
|
||||||
|
@ -851,10 +847,9 @@ func abs(n int32) int32 {
|
||||||
|
|
||||||
// Cmp compares the numbers represented by d and d2 and returns:
|
// Cmp compares the numbers represented by d and d2 and returns:
|
||||||
//
|
//
|
||||||
// -1 if d < d2
|
// -1 if d < d2
|
||||||
// 0 if d == d2
|
// 0 if d == d2
|
||||||
// +1 if d > d2
|
// +1 if d > d2
|
||||||
//
|
|
||||||
func (d Decimal) Cmp(d2 Decimal) int {
|
func (d Decimal) Cmp(d2 Decimal) int {
|
||||||
d.ensureInitialized()
|
d.ensureInitialized()
|
||||||
d2.ensureInitialized()
|
d2.ensureInitialized()
|
||||||
|
@ -905,7 +900,6 @@ func (d Decimal) LessThanOrEqual(d2 Decimal) bool {
|
||||||
// -1 if d < 0
|
// -1 if d < 0
|
||||||
// 0 if d == 0
|
// 0 if d == 0
|
||||||
// +1 if d > 0
|
// +1 if d > 0
|
||||||
//
|
|
||||||
func (d Decimal) Sign() int {
|
func (d Decimal) Sign() int {
|
||||||
if d.value == nil {
|
if d.value == nil {
|
||||||
return 0
|
return 0
|
||||||
|
@ -1014,13 +1008,12 @@ func (d Decimal) InexactFloat64() float64 {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// d := New(-12345, -3)
|
// d := New(-12345, -3)
|
||||||
// println(d.String())
|
// println(d.String())
|
||||||
//
|
//
|
||||||
// Output:
|
// Output:
|
||||||
//
|
//
|
||||||
// -12.345
|
// -12.345
|
||||||
//
|
|
||||||
func (d Decimal) String() string {
|
func (d Decimal) String() string {
|
||||||
return d.string(true)
|
return d.string(true)
|
||||||
}
|
}
|
||||||
|
@ -1030,14 +1023,13 @@ func (d Decimal) String() string {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(0).StringFixed(2) // output: "0.00"
|
// NewFromFloat(0).StringFixed(2) // output: "0.00"
|
||||||
// NewFromFloat(0).StringFixed(0) // output: "0"
|
// NewFromFloat(0).StringFixed(0) // output: "0"
|
||||||
// NewFromFloat(5.45).StringFixed(0) // output: "5"
|
// NewFromFloat(5.45).StringFixed(0) // output: "5"
|
||||||
// NewFromFloat(5.45).StringFixed(1) // output: "5.5"
|
// NewFromFloat(5.45).StringFixed(1) // output: "5.5"
|
||||||
// NewFromFloat(5.45).StringFixed(2) // output: "5.45"
|
// NewFromFloat(5.45).StringFixed(2) // output: "5.45"
|
||||||
// NewFromFloat(5.45).StringFixed(3) // output: "5.450"
|
// NewFromFloat(5.45).StringFixed(3) // output: "5.450"
|
||||||
// NewFromFloat(545).StringFixed(-1) // output: "550"
|
// NewFromFloat(545).StringFixed(-1) // output: "550"
|
||||||
//
|
|
||||||
func (d Decimal) StringFixed(places int32) string {
|
func (d Decimal) StringFixed(places int32) string {
|
||||||
rounded := d.Round(places)
|
rounded := d.Round(places)
|
||||||
return rounded.string(false)
|
return rounded.string(false)
|
||||||
|
@ -1048,14 +1040,13 @@ func (d Decimal) StringFixed(places int32) string {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(0).StringFixedBank(2) // output: "0.00"
|
// NewFromFloat(0).StringFixedBank(2) // output: "0.00"
|
||||||
// NewFromFloat(0).StringFixedBank(0) // output: "0"
|
// NewFromFloat(0).StringFixedBank(0) // output: "0"
|
||||||
// NewFromFloat(5.45).StringFixedBank(0) // output: "5"
|
// NewFromFloat(5.45).StringFixedBank(0) // output: "5"
|
||||||
// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4"
|
// NewFromFloat(5.45).StringFixedBank(1) // output: "5.4"
|
||||||
// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45"
|
// NewFromFloat(5.45).StringFixedBank(2) // output: "5.45"
|
||||||
// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450"
|
// NewFromFloat(5.45).StringFixedBank(3) // output: "5.450"
|
||||||
// NewFromFloat(545).StringFixedBank(-1) // output: "540"
|
// NewFromFloat(545).StringFixedBank(-1) // output: "540"
|
||||||
//
|
|
||||||
func (d Decimal) StringFixedBank(places int32) string {
|
func (d Decimal) StringFixedBank(places int32) string {
|
||||||
rounded := d.RoundBank(places)
|
rounded := d.RoundBank(places)
|
||||||
return rounded.string(false)
|
return rounded.string(false)
|
||||||
|
@ -1073,9 +1064,8 @@ func (d Decimal) StringFixedCash(interval uint8) string {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(5.45).Round(1).String() // output: "5.5"
|
// NewFromFloat(5.45).Round(1).String() // output: "5.5"
|
||||||
// NewFromFloat(545).Round(-1).String() // output: "550"
|
// NewFromFloat(545).Round(-1).String() // output: "550"
|
||||||
//
|
|
||||||
func (d Decimal) Round(places int32) Decimal {
|
func (d Decimal) Round(places int32) Decimal {
|
||||||
if d.exp == -places {
|
if d.exp == -places {
|
||||||
return d
|
return d
|
||||||
|
@ -1104,11 +1094,10 @@ func (d Decimal) Round(places int32) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(545).RoundCeil(-2).String() // output: "600"
|
// NewFromFloat(545).RoundCeil(-2).String() // output: "600"
|
||||||
// NewFromFloat(500).RoundCeil(-2).String() // output: "500"
|
// NewFromFloat(500).RoundCeil(-2).String() // output: "500"
|
||||||
// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11"
|
// NewFromFloat(1.1001).RoundCeil(2).String() // output: "1.11"
|
||||||
// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5"
|
// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5"
|
||||||
//
|
|
||||||
func (d Decimal) RoundCeil(places int32) Decimal {
|
func (d Decimal) RoundCeil(places int32) Decimal {
|
||||||
if d.exp >= -places {
|
if d.exp >= -places {
|
||||||
return d
|
return d
|
||||||
|
@ -1130,11 +1119,10 @@ func (d Decimal) RoundCeil(places int32) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(545).RoundFloor(-2).String() // output: "500"
|
// NewFromFloat(545).RoundFloor(-2).String() // output: "500"
|
||||||
// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500"
|
// NewFromFloat(-500).RoundFloor(-2).String() // output: "-500"
|
||||||
// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1"
|
// NewFromFloat(1.1001).RoundFloor(2).String() // output: "1.1"
|
||||||
// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4"
|
// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4"
|
||||||
//
|
|
||||||
func (d Decimal) RoundFloor(places int32) Decimal {
|
func (d Decimal) RoundFloor(places int32) Decimal {
|
||||||
if d.exp >= -places {
|
if d.exp >= -places {
|
||||||
return d
|
return d
|
||||||
|
@ -1156,11 +1144,10 @@ func (d Decimal) RoundFloor(places int32) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(545).RoundUp(-2).String() // output: "600"
|
// NewFromFloat(545).RoundUp(-2).String() // output: "600"
|
||||||
// NewFromFloat(500).RoundUp(-2).String() // output: "500"
|
// NewFromFloat(500).RoundUp(-2).String() // output: "500"
|
||||||
// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11"
|
// NewFromFloat(1.1001).RoundUp(2).String() // output: "1.11"
|
||||||
// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4"
|
// NewFromFloat(-1.454).RoundUp(1).String() // output: "-1.4"
|
||||||
//
|
|
||||||
func (d Decimal) RoundUp(places int32) Decimal {
|
func (d Decimal) RoundUp(places int32) Decimal {
|
||||||
if d.exp >= -places {
|
if d.exp >= -places {
|
||||||
return d
|
return d
|
||||||
|
@ -1184,11 +1171,10 @@ func (d Decimal) RoundUp(places int32) Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// NewFromFloat(545).RoundDown(-2).String() // output: "500"
|
// NewFromFloat(545).RoundDown(-2).String() // output: "500"
|
||||||
// NewFromFloat(-500).RoundDown(-2).String() // output: "-500"
|
// NewFromFloat(-500).RoundDown(-2).String() // output: "-500"
|
||||||
// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1"
|
// NewFromFloat(1.1001).RoundDown(2).String() // output: "1.1"
|
||||||
// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5"
|
// NewFromFloat(-1.454).RoundDown(1).String() // output: "-1.5"
|
||||||
//
|
|
||||||
func (d Decimal) RoundDown(places int32) Decimal {
|
func (d Decimal) RoundDown(places int32) Decimal {
|
||||||
if d.exp >= -places {
|
if d.exp >= -places {
|
||||||
return d
|
return d
|
||||||
|
@ -1209,13 +1195,12 @@ func (d Decimal) RoundDown(places int32) Decimal {
|
||||||
//
|
//
|
||||||
// Examples:
|
// Examples:
|
||||||
//
|
//
|
||||||
// NewFromFloat(5.45).RoundBank(1).String() // output: "5.4"
|
// NewFromFloat(5.45).RoundBank(1).String() // output: "5.4"
|
||||||
// NewFromFloat(545).RoundBank(-1).String() // output: "540"
|
// NewFromFloat(545).RoundBank(-1).String() // output: "540"
|
||||||
// NewFromFloat(5.46).RoundBank(1).String() // output: "5.5"
|
// NewFromFloat(5.46).RoundBank(1).String() // output: "5.5"
|
||||||
// NewFromFloat(546).RoundBank(-1).String() // output: "550"
|
// NewFromFloat(546).RoundBank(-1).String() // output: "550"
|
||||||
// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6"
|
// NewFromFloat(5.55).RoundBank(1).String() // output: "5.6"
|
||||||
// NewFromFloat(555).RoundBank(-1).String() // output: "560"
|
// NewFromFloat(555).RoundBank(-1).String() // output: "560"
|
||||||
//
|
|
||||||
func (d Decimal) RoundBank(places int32) Decimal {
|
func (d Decimal) RoundBank(places int32) Decimal {
|
||||||
|
|
||||||
round := d.Round(places)
|
round := d.Round(places)
|
||||||
|
@ -1237,11 +1222,13 @@ func (d Decimal) RoundBank(places int32) Decimal {
|
||||||
// interval. The amount payable for a cash transaction is rounded to the nearest
|
// interval. The amount payable for a cash transaction is rounded to the nearest
|
||||||
// multiple of the minimum currency unit available. The following intervals are
|
// multiple of the minimum currency unit available. The following intervals are
|
||||||
// available: 5, 10, 25, 50 and 100; any other number throws a panic.
|
// available: 5, 10, 25, 50 and 100; any other number throws a panic.
|
||||||
// 5: 5 cent rounding 3.43 => 3.45
|
//
|
||||||
// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up)
|
// 5: 5 cent rounding 3.43 => 3.45
|
||||||
// 25: 25 cent rounding 3.41 => 3.50
|
// 10: 10 cent rounding 3.45 => 3.50 (5 gets rounded up)
|
||||||
// 50: 50 cent rounding 3.75 => 4.00
|
// 25: 25 cent rounding 3.41 => 3.50
|
||||||
// 100: 100 cent rounding 3.50 => 4.00
|
// 50: 50 cent rounding 3.75 => 4.00
|
||||||
|
// 100: 100 cent rounding 3.50 => 4.00
|
||||||
|
//
|
||||||
// For more details: https://en.wikipedia.org/wiki/Cash_rounding
|
// For more details: https://en.wikipedia.org/wiki/Cash_rounding
|
||||||
func (d Decimal) RoundCash(interval uint8) Decimal {
|
func (d Decimal) RoundCash(interval uint8) Decimal {
|
||||||
var iVal *big.Int
|
var iVal *big.Int
|
||||||
|
@ -1310,8 +1297,7 @@ func (d Decimal) Ceil() Decimal {
|
||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// decimal.NewFromString("123.456").Truncate(2).String() // "123.45"
|
// decimal.NewFromString("123.456").Truncate(2).String() // "123.45"
|
||||||
//
|
|
||||||
func (d Decimal) Truncate(precision int32) Decimal {
|
func (d Decimal) Truncate(precision int32) Decimal {
|
||||||
d.ensureInitialized()
|
d.ensureInitialized()
|
||||||
if precision >= 0 && -precision > d.exp {
|
if precision >= 0 && -precision > d.exp {
|
||||||
|
@ -1330,7 +1316,10 @@ func (d *Decimal) UnmarshalJSON(decimalBytes []byte) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error decoding string '%s': %s", decimalBytes, err)
|
return fmt.Errorf("error decoding string '%s': %s", decimalBytes, err)
|
||||||
}
|
}
|
||||||
|
if len(str) == 0 {
|
||||||
|
*d = Zero
|
||||||
|
return nil
|
||||||
|
}
|
||||||
decimal, err := NewFromString(str)
|
decimal, err := NewFromString(str)
|
||||||
*d = decimal
|
*d = decimal
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1515,7 +1504,7 @@ func (d *Decimal) ensureInitialized() {
|
||||||
//
|
//
|
||||||
// To call this function with an array, you must do:
|
// To call this function with an array, you must do:
|
||||||
//
|
//
|
||||||
// Min(arr[0], arr[1:]...)
|
// Min(arr[0], arr[1:]...)
|
||||||
//
|
//
|
||||||
// This makes it harder to accidentally call Min with 0 arguments.
|
// This makes it harder to accidentally call Min with 0 arguments.
|
||||||
func Min(first Decimal, rest ...Decimal) Decimal {
|
func Min(first Decimal, rest ...Decimal) Decimal {
|
||||||
|
@ -1532,7 +1521,7 @@ func Min(first Decimal, rest ...Decimal) Decimal {
|
||||||
//
|
//
|
||||||
// To call this function with an array, you must do:
|
// To call this function with an array, you must do:
|
||||||
//
|
//
|
||||||
// Max(arr[0], arr[1:]...)
|
// Max(arr[0], arr[1:]...)
|
||||||
//
|
//
|
||||||
// This makes it harder to accidentally call Max with 0 arguments.
|
// This makes it harder to accidentally call Max with 0 arguments.
|
||||||
func Max(first Decimal, rest ...Decimal) Decimal {
|
func Max(first Decimal, rest ...Decimal) Decimal {
|
||||||
|
@ -1599,7 +1588,7 @@ func unquoteIfQuoted(value interface{}) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the amount is quoted, strip the quotes
|
// If the amount is quoted, strip the quotes
|
||||||
if len(bytes) > 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' {
|
if len(bytes) >= 2 && bytes[0] == '"' && bytes[len(bytes)-1] == '"' {
|
||||||
bytes = bytes[1 : len(bytes)-1]
|
bytes = bytes[1 : len(bytes)-1]
|
||||||
}
|
}
|
||||||
return string(bytes), nil
|
return string(bytes), nil
|
||||||
|
|
|
@ -623,12 +623,26 @@ func TestUnmarshalJSONNull(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalJSONEmptyString(t *testing.T) {
|
||||||
|
var doc struct {
|
||||||
|
Amount Decimal `json:"amount"`
|
||||||
|
}
|
||||||
|
docStr := `{"amount": ""}`
|
||||||
|
err := json.Unmarshal([]byte(docStr), &doc)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("error unmarshaling %s: %v", docStr, err)
|
||||||
|
} else if !doc.Amount.Equal(Zero) {
|
||||||
|
t.Errorf("expected Zero, got %s (%s, %d)",
|
||||||
|
doc.Amount.String(),
|
||||||
|
doc.Amount.value.String(), doc.Amount.exp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestBadJSON(t *testing.T) {
|
func TestBadJSON(t *testing.T) {
|
||||||
for _, testCase := range []string{
|
for _, testCase := range []string{
|
||||||
"]o_o[",
|
"]o_o[",
|
||||||
"{",
|
"{",
|
||||||
`{"amount":""`,
|
`{"amount":""`,
|
||||||
`{"amount":""}`,
|
|
||||||
`{"amount":"nope"}`,
|
`{"amount":"nope"}`,
|
||||||
`0.333`,
|
`0.333`,
|
||||||
} {
|
} {
|
||||||
|
@ -720,7 +734,6 @@ func TestNullDecimalBadJSON(t *testing.T) {
|
||||||
"]o_o[",
|
"]o_o[",
|
||||||
"{",
|
"{",
|
||||||
`{"amount":""`,
|
`{"amount":""`,
|
||||||
`{"amount":""}`,
|
|
||||||
`{"amount":"nope"}`,
|
`{"amount":"nope"}`,
|
||||||
`{"amount":nope}`,
|
`{"amount":nope}`,
|
||||||
`0.333`,
|
`0.333`,
|
||||||
|
|
Loading…
Reference in a new issue