Skip to content

Commit ecc1fd1

Browse files
author
wayn3h0
committed
feat: add functions for Money type
1. *Money.IsZero 2. *Money.RoundToNearestEven 3. *Money.RoundToNearestAway 4. *Money.RoundToZero 5. *Money.Round 6. *Money.Truncate
1 parent a3c1575 commit ecc1fd1

File tree

2 files changed

+121
-41
lines changed

2 files changed

+121
-41
lines changed

money.go

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -7,70 +7,117 @@ import (
77
"github.com/golang-plus/math/big"
88
)
99

10-
// Money represents an amount of a specific currency.
10+
// Money represents an amount (with precision 4) of a specific currency.
1111
type Money struct {
12+
amount *big.Decimal
1213
Currency *Currency
1314
Amount float64
14-
decimal *big.Decimal
15-
}
16-
17-
// NewMoney returns a new money.
18-
func NewMoney(currency *Currency, amount float64) (*Money, error) {
19-
if currency == nil {
20-
return nil, errors.New("currency of money cannot be nil")
21-
}
22-
23-
return &Money{
24-
Currency: currency,
25-
Amount: amount,
26-
decimal: big.NewDecimal(amount),
27-
}, nil
28-
}
29-
30-
// MustNewMoney is like as NewMoney but panic if error happens.
31-
func MustNewMoney(currency *Currency, amount float64) *Money {
32-
money, err := NewMoney(currency, amount)
33-
if err != nil {
34-
panic(err)
35-
}
36-
37-
return money
3815
}
3916

4017
// Format returns the formatted string of money.
4118
func (m *Money) Format(formatter *CurrencyFormatter) string {
4219
return formatter.Format(m.Amount)
4320
}
4421

45-
// String returns the string of money (format: currency code + amount).
22+
// String returns the formatted string (format: currency code + amount).
4623
func (m *Money) String() string {
4724
return fmt.Sprintf("%s %f", m.Currency.Code, m.Amount)
4825
}
4926

50-
// Add sets m.decimal to the sum of m.decimal and another and returns m.
27+
// IsZero reports whether the amount is euqal to zero.
28+
func (m *Money) IsZero() bool {
29+
return m.amount.IsZero()
30+
}
31+
32+
// Sign returns:
33+
// -1: if m < 0
34+
// 0: if m == 0
35+
// +1: if m > 0
36+
func (m *Money) Sign() int {
37+
return m.amount.Sign()
38+
}
39+
40+
// Add sets amount to the sum of amount and x then returns m.
5141
func (m *Money) Add(x float64) *Money {
52-
m.decimal.Add(big.NewDecimal(x))
53-
m.Amount = m.decimal.Float64()
42+
m.amount.Add(big.NewDecimal(x))
43+
m.Amount, _ = m.amount.Float64()
5444
return m
5545
}
5646

57-
// Sub sets m.decimal to the difference m.decimal-another and returns m.
47+
// Sub sets amount to the difference amount-x then returns m.
5848
func (m *Money) Sub(x float64) *Money {
59-
m.decimal.Sub(big.NewDecimal(x))
60-
m.Amount = m.decimal.Float64()
49+
m.amount.Sub(big.NewDecimal(x))
50+
m.Amount, _ = m.amount.Float64()
6151
return m
6252
}
6353

64-
// Mul sets m.decimal to the product m.decimal*another and returns m.
54+
// Mul sets amount to the product amount*x and returns m.
6555
func (m *Money) Mul(x float64) *Money {
66-
m.decimal.Mul(big.NewDecimal(x))
67-
m.Amount = m.decimal.Float64()
56+
m.amount.Mul(big.NewDecimal(x))
57+
m.Amount, _ = m.amount.Float64()
6858
return m
6959
}
7060

71-
// Div sets m.decimal to the quotient m/another and return m.
61+
// Div sets amount to the quotient amount/x and return m.
7262
func (m *Money) Div(x float64) *Money {
73-
m.decimal.Div(big.NewDecimal(x))
74-
m.Amount = m.decimal.Float64()
63+
m.amount.Div(big.NewDecimal(x))
64+
m.Amount, _ = m.amount.Float64()
7565
return m
7666
}
67+
68+
// RoundToNearestEven rounds the amount by "To Nearest Even" mode with 4 precision.
69+
// precision indicates the number of digits after the decimal point.
70+
func (m *Money) RoundToNearestEven(precision uint) *Money {
71+
m.amount.RoundToNearestEven(precision)
72+
m.Amount, _ = m.amount.Float64()
73+
return m
74+
}
75+
76+
// RoundToNearestEven rounds the amount by "To Nearest Away From Zero" mode with 4 precision.
77+
// precision indicates the number of digits after the decimal point.
78+
func (m *Money) RoundToNearestAway(precision uint) *Money {
79+
m.amount.RoundToNearestAway(precision)
80+
m.Amount, _ = m.amount.Float64()
81+
return m
82+
}
83+
84+
// RoundToZero rounds the amount by "To Zero" mode with 4 precision.
85+
// precision indicates the number of digits after the decimal point.
86+
func (m *Money) RoundToZero(precision uint) *Money {
87+
m.amount.RoundToZero(precision)
88+
m.Amount, _ = m.amount.Float64()
89+
return m
90+
}
91+
92+
// Round is same as RoundToNearestEven.
93+
func (m *Money) Round(precision uint) *Money {
94+
return m.RoundToNearestEven(precision)
95+
}
96+
97+
// Truncate is same as RoundToZero.
98+
func (m *Money) Truncate(precision uint) *Money {
99+
return m.RoundToZero(precision)
100+
}
101+
102+
// NewMoney returns a new money.
103+
func NewMoney(currency *Currency, amount float64) (*Money, error) {
104+
if currency == nil {
105+
return nil, errors.New("currency of money cannot be nil")
106+
}
107+
108+
return &Money{
109+
amount: big.NewDecimal(amount),
110+
Currency: currency,
111+
Amount: amount,
112+
}, nil
113+
}
114+
115+
// MustNewMoney is like as NewMoney but panic if error happens.
116+
func MustNewMoney(currency *Currency, amount float64) *Money {
117+
money, err := NewMoney(currency, amount)
118+
if err != nil {
119+
panic(err)
120+
}
121+
122+
return money
123+
}

money_test.go

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,41 @@ func TestMoney(t *testing.T) {
1717
GroupSeparator: ",",
1818
}
1919

20-
m := MustNewMoney(GetCurrency("USD"), -1.0)
21-
m.Add(100).Sub(55).Div(2.5).Mul(2)
20+
// calculation:
21+
data := map[string][4]float64{
22+
"-$0.8250": {1.1, 2.2, 3.3, 4.4},
23+
"$2.2000": {4.4, 3.3, 2.2, 1.1},
24+
"$22.2200": {44.44, 33.33, 22.22, 11.11},
25+
"$2,222.2222": {4444.4444, 3333.3333, 2222.2222, 1111.1111},
26+
"-$833.3333": {1111.1111, 2222.2222, 3333.3333, 4444.4444},
27+
}
28+
for k, v := range data {
29+
m := MustNewMoney(GetCurrency("usd"), 0)
30+
// + - * /
31+
m.Add(v[0]).Sub(v[1]).Mul(v[2]).Div(v[3])
32+
testing2.AssertEqual(t, m.Format(cf), k)
33+
}
34+
35+
// rounding:
36+
37+
// to nearest even
38+
data2 := map[float64]float64{
39+
2.34564: 2.3456,
40+
2.34566: 2.3457,
41+
2.34605001: 2.3461,
42+
2.34635: 2.3464,
43+
2.34645: 2.3464,
44+
-2.34564: -2.3456,
45+
-2.34566: -2.3457,
46+
-2.34605001: -2.3461,
47+
-2.34635: -2.3464,
48+
-2.34645: -2.3464,
49+
2.34555: 2.3456,
50+
2.34525: 2.3452,
51+
}
52+
for k, v := range data2 {
53+
m := MustNewMoney(GetCurrency("usd"), k)
54+
testing2.AssertEqual(t, m.RoundToNearestEven(4).Amount, v)
55+
}
2256

23-
testing2.AssertEqual(t, m.Format(cf), "$35.2000")
2457
}

0 commit comments

Comments
 (0)