From 807eb918f4c345e83a139bb99f73120d08ab12cf Mon Sep 17 00:00:00 2001 From: Quang Mai Date: Sat, 4 Jan 2025 19:13:48 +0700 Subject: [PATCH] feat: add comparison utilities --- decimal.go | 43 +++++++++++++++++ decimal_test.go | 125 +++++++++++++++++++++++++++++++++++------------- doc_test.go | 52 ++++++++++++++++++++ 3 files changed, 188 insertions(+), 32 deletions(-) diff --git a/decimal.go b/decimal.go index b5f4e9d..c719e1e 100644 --- a/decimal.go +++ b/decimal.go @@ -742,6 +742,49 @@ func (d Decimal) Equal(e Decimal) bool { return d.Cmp(e) == 0 } +// LessThan reports whether d < e. +func (d Decimal) LessThan(e Decimal) bool { + return d.Cmp(e) == -1 +} + +// LessThanOrEqual reports whether d <= e. +func (d Decimal) LessThanOrEqual(e Decimal) bool { + return d.Cmp(e) <= 0 +} + +// GreaterThan reports whether d > e. +func (d Decimal) GreaterThan(e Decimal) bool { + return d.Cmp(e) == 1 +} + +// GreaterThanOrEqual reports whether d >= e. +func (d Decimal) GreaterThanOrEqual(e Decimal) bool { + return d.Cmp(e) >= 0 +} + +// Max returns the maximum decimal from the list of decimals. +func Max(a Decimal, b ...Decimal) Decimal { + result := a + for _, v := range b { + if v.GreaterThan(result) { + result = v + } + } + + return result +} + +func Min(a Decimal, b ...Decimal) Decimal { + result := a + for _, v := range b { + if v.LessThan(result) { + result = v + } + } + + return result +} + func (d Decimal) cmpDecSameSign(e Decimal) int { result, err := tryCmpU128(d, e) if err == nil { diff --git a/decimal_test.go b/decimal_test.go index 55b203c..11dde5d 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -1275,36 +1275,40 @@ func TestCmp(t *testing.T) { } } -func TestEqual(t *testing.T) { +func TestComparisionUtils(t *testing.T) { testcases := []struct { - a, b string - want bool + a, b string + wantEqual bool + wantLT bool + wantLTE bool + wantGT bool + wantGTE bool }{ - {"1234567890123456789", "0", false}, - {"123.123", "-123.123", false}, - {"-123.123", "123.123", false}, - {"-123.123", "-123.123", true}, - {"-123.123", "-123.1234567890123456789", false}, - {"123.123", "123.1234567890123456789", false}, - {"123.123", "123.1230000000000000001", false}, - {"-123.123", "-123.1230000000000000001", false}, - {"123.1230000000000000002", "123.1230000000000000001", false}, - {"-123.1230000000000000002", "-123.1230000000000000001", false}, - {"123.1230000000000000002", "123.123000000001", false}, - {"-123.1230000000000000002", "-123.123000000001", false}, - {"123.123", "123.1230000", true}, - {"123.101", "123.1001", false}, - {"1000000000000000000000000.1234567890123456789", "1.1234567890123456789", false}, - {"-1000000000000000000000000.1234567890123456789", "1.1234567890123456789", false}, - {"-1000000000000000000000000.1234567890123456789", "-1.1234567890123456789", false}, - {"1000000000000000000000000.1234567890123456789", "1000000000000000000000000.1234567890123456789", true}, - {"-1000000000000000000000000.1234567890123456789", "-1000000000000000000000000.1234567890123456789", true}, - {"1000000000000000000000000.1234567890123456789", "1000000000000000000000000.1234567890123456788", false}, - {"-1000000000000000000000000.1234567890123456789", "-1000000000000000000000000.1234567890123456788", false}, - {"1000000000000000000000000.12345678901234", "1000000000000000000000000.1234567890123456788", false}, - {"-1000000000000000000000000.12345678901234", "-1000000000000000000000000.1234567890123456788", false}, - {"1000000000000000000000000.1234567890123456788", "1000000000000000000000000.12345678901234", false}, - {"-1000000000000000000000000.1234567890123456788", "-1000000000000000000000000.12345678901234", false}, + {"1234567890123456789", "0", false, false, false, true, true}, + {"123.123", "-123.123", false, false, false, true, true}, + {"-123.123", "123.123", false, true, true, false, false}, + {"-123.123", "-123.123", true, false, true, false, true}, + {"-123.123", "-123.1234567890123456789", false, false, false, true, true}, + {"123.123", "123.1234567890123456789", false, true, true, false, false}, + {"123.123", "123.1230000000000000001", false, true, true, false, false}, + {"-123.123", "-123.1230000000000000001", false, false, false, true, true}, + {"123.1230000000000000002", "123.1230000000000000001", false, false, false, true, true}, + {"-123.1230000000000000002", "-123.1230000000000000001", false, true, true, false, false}, + {"123.1230000000000000002", "123.123000000001", false, true, true, false, false}, + {"-123.1230000000000000002", "-123.123000000001", false, false, false, true, true}, + {"123.123", "123.1230000", true, false, true, false, true}, + {"123.101", "123.1001", false, false, false, true, true}, + {"1000000000000000000000000.1234567890123456789", "1.1234567890123456789", false, false, false, true, true}, + {"-1000000000000000000000000.1234567890123456789", "1.1234567890123456789", false, true, true, false, false}, + {"-1000000000000000000000000.1234567890123456789", "-1.1234567890123456789", false, true, true, false, false}, + {"1000000000000000000000000.1234567890123456789", "1000000000000000000000000.1234567890123456789", true, false, true, false, true}, + {"-1000000000000000000000000.1234567890123456789", "-1000000000000000000000000.1234567890123456789", true, false, true, false, true}, + {"1000000000000000000000000.1234567890123456789", "1000000000000000000000000.1234567890123456788", false, false, false, true, true}, + {"-1000000000000000000000000.1234567890123456789", "-1000000000000000000000000.1234567890123456788", false, true, true, false, false}, + {"1000000000000000000000000.12345678901234", "1000000000000000000000000.1234567890123456788", false, true, true, false, false}, + {"-1000000000000000000000000.12345678901234", "-1000000000000000000000000.1234567890123456788", false, false, false, true, true}, + {"1000000000000000000000000.1234567890123456788", "1000000000000000000000000.12345678901234", false, false, false, true, true}, + {"-1000000000000000000000000.1234567890123456788", "-1000000000000000000000000.12345678901234", false, true, true, false, false}, } for _, tc := range testcases { @@ -1315,19 +1319,76 @@ func TestEqual(t *testing.T) { b, err := Parse(tc.b) require.NoError(t, err) - c := a.Equal(b) - require.Equal(t, tc.want, c) - - // compare with shopspring/decimal aa := decimal.RequireFromString(tc.a) bb := decimal.RequireFromString(tc.b) + // test equal + c := a.Equal(b) cc := aa.Equal(bb) + require.Equal(t, tc.wantEqual, c) + require.Equal(t, cc, c) + + // test less than + c = a.LessThan(b) + cc = aa.LessThan(bb) + require.Equal(t, tc.wantLT, c) + require.Equal(t, cc, c) + + // test less than or equal + c = a.LessThanOrEqual(b) + cc = aa.LessThanOrEqual(bb) + require.Equal(t, tc.wantLTE, c) + require.Equal(t, cc, c) + + // test greater than + c = a.GreaterThan(b) + cc = aa.GreaterThan(bb) + require.Equal(t, tc.wantGT, c) + require.Equal(t, cc, c) + + // test greater than or equal + c = a.GreaterThanOrEqual(b) + cc = aa.GreaterThanOrEqual(bb) + require.Equal(t, tc.wantGTE, c) require.Equal(t, cc, c) }) } } +func TestMaxMin(t *testing.T) { + testcases := []struct { + list []string + wantMax string + wantMin string + }{ + {[]string{"1234567890123456789", "0", "1234567890123456789", "1234567890123456789"}, "1234567890123456789", "0"}, + {[]string{"123.123", "-123.123", "123.123", "-123.123"}, "123.123", "-123.123"}, + {[]string{"-1235.123124235235", "0.11", "5345.29809824", "-6465465.45646"}, "5345.29809824", "-6465465.45646"}, + {[]string{"1.123", "2.235"}, "2.235", "1.123"}, + {[]string{"-1.123", "-2.235"}, "-1.123", "-2.235"}, + {[]string{"1.123"}, "1.123", "1.123"}, + } + + for _, tc := range testcases { + t.Run(fmt.Sprintf("%v", tc.list), func(t *testing.T) { + list := make([]Decimal, len(tc.list)) + for i, s := range tc.list { + d, err := Parse(s) + require.NoError(t, err) + list[i] = d + } + + // test max + expectedMax := Max(list[0], list[1:]...) + require.Equal(t, tc.wantMax, expectedMax.String()) + + // test min + expectedMin := Min(list[0], list[1:]...) + require.Equal(t, tc.wantMin, expectedMin.String()) + }) + } +} + func TestCmpWithDifferentPrecision(t *testing.T) { testcases := []struct { a1, a2, b string diff --git a/doc_test.go b/doc_test.go index 5f3378f..2b91f3d 100644 --- a/doc_test.go +++ b/doc_test.go @@ -146,6 +146,58 @@ func ExampleDecimal_Cmp() { // 1 } +func ExampleDecimal_LessThan() { + fmt.Println(MustParse("1.23").LessThan(MustParse("4.12475"))) + fmt.Println(MustParse("1.23").LessThan(MustParse("1.23"))) + fmt.Println(MustParse("1.23").LessThan(MustParse("0.12475"))) + // Output: + // true + // false + // false +} + +func ExampleDecimal_LessThanOrEqual() { + fmt.Println(MustParse("1.23").LessThanOrEqual(MustParse("4.12475"))) + fmt.Println(MustParse("1.23").LessThanOrEqual(MustParse("1.23"))) + fmt.Println(MustParse("1.23").LessThanOrEqual(MustParse("0.12475"))) + // Output: + // true + // true + // false +} + +func ExampleDecimal_GreaterThan() { + fmt.Println(MustParse("1.23").GreaterThan(MustParse("4.12475"))) + fmt.Println(MustParse("1.23").GreaterThan(MustParse("1.23"))) + fmt.Println(MustParse("1.23").GreaterThan(MustParse("0.12475"))) + // Output: + // false + // false + // true +} + +func ExampleDecimal_GreaterThanOrEqual() { + fmt.Println(MustParse("1.23").GreaterThanOrEqual(MustParse("4.12475"))) + fmt.Println(MustParse("1.23").GreaterThanOrEqual(MustParse("1.23"))) + fmt.Println(MustParse("1.23").GreaterThanOrEqual(MustParse("0.12475"))) + // Output: + // false + // true + // true +} + +func ExampleMax() { + fmt.Println(Max(MustParse("1.23"), MustParse("4.12475"))) + // Output: + // 4.12475 +} + +func ExampleMin() { + fmt.Println(Min(MustParse("1.23"), MustParse("4.12475"))) + // Output: + // 1.23 +} + func ExampleDecimal_Equal() { fmt.Println(MustParse("1.123").Equal(MustParse("-1.123"))) fmt.Println(MustParse("1.123").Equal(MustParse("1.1230000")))