From 8d1104417f7bc2fa16b7129592b3ff393b0a7dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drake=20=28V=C5=A9=20Long=29?= Date: Sun, 7 Mar 2021 18:10:04 +0700 Subject: [PATCH 1/3] Change function name from RoundUp -> RoundCeil, RoundDown -> RoundFloor --- decimal.go | 24 ++++++++++++------------ decimal_test.go | 12 ++++++------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/decimal.go b/decimal.go index e68ad2c8..462f7f61 100644 --- a/decimal.go +++ b/decimal.go @@ -892,16 +892,16 @@ func (d Decimal) Round(places int32) Decimal { return ret } -// RoundUp rounds the decimal towards +infinity. +// RoundCeil rounds the decimal towards +infinity. // // Example: // -// 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" +// 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.4" // -func (d Decimal) RoundUp(places int32) Decimal { +func (d Decimal) RoundCeil(places int32) Decimal { if d.exp >= -places { return d } @@ -918,16 +918,16 @@ func (d Decimal) RoundUp(places int32) Decimal { return rescaled } -// RoundDown rounds the decimal towards -infinity. +// RoundFloor rounds the decimal towards -infinity. // // Example: // -// 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" +// 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.5" // -func (d Decimal) RoundDown(places int32) Decimal { +func (d Decimal) RoundFloor(places int32) Decimal { if d.exp >= -places { return d } diff --git a/decimal_test.go b/decimal_test.go index 1bfca281..40f27cc1 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -1084,7 +1084,7 @@ func TestDecimal_RoundAndStringFixed(t *testing.T) { } } -func TestDecimal_RoundUpAndStringFixed(t *testing.T) { +func TestDecimal_RoundCeilAndStringFixed(t *testing.T) { type testData struct { input string places int32 @@ -1157,9 +1157,9 @@ func TestDecimal_RoundUpAndStringFixed(t *testing.T) { if err != nil { t.Fatal(err) } - got := d.RoundUp(test.places) + got := d.RoundCeil(test.places) if !got.Equal(expected) { - t.Errorf("Rounding up %s to %d places, got %s, expected %s", + t.Errorf("Rounding ceil %s to %d places, got %s, expected %s", d, test.places, got, expected) } @@ -1175,7 +1175,7 @@ func TestDecimal_RoundUpAndStringFixed(t *testing.T) { } } -func TestDecimal_RoundDownAndStringFixed(t *testing.T) { +func TestDecimal_RoundFloorAndStringFixed(t *testing.T) { type testData struct { input string places int32 @@ -1248,9 +1248,9 @@ func TestDecimal_RoundDownAndStringFixed(t *testing.T) { if err != nil { t.Fatal(err) } - got := d.RoundDown(test.places) + got := d.RoundFloor(test.places) if !got.Equal(expected) { - t.Errorf("Rounding down %s to %d places, got %s, expected %s", + t.Errorf("Rounding floor %s to %d places, got %s, expected %s", d, test.places, got, expected) } From b9353a2617dc5f4a88df66cd4d0abd59802bfb21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drake=20=28V=C5=A9=20Long=29?= Date: Sun, 7 Mar 2021 18:27:23 +0700 Subject: [PATCH 2/3] Add a new RoundUp and RoundDown methods --- decimal.go | 53 +++++++++++++- decimal_test.go | 182 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 233 insertions(+), 2 deletions(-) diff --git a/decimal.go b/decimal.go index 462f7f61..6a0040d4 100644 --- a/decimal.go +++ b/decimal.go @@ -899,7 +899,7 @@ func (d Decimal) Round(places int32) Decimal { // 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.4" +// NewFromFloat(-1.454).RoundCeil(1).String() // output: "-1.5" // func (d Decimal) RoundCeil(places int32) Decimal { if d.exp >= -places { @@ -925,7 +925,7 @@ func (d Decimal) RoundCeil(places int32) Decimal { // 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.5" +// NewFromFloat(-1.454).RoundFloor(1).String() // output: "-1.4" // func (d Decimal) RoundFloor(places int32) Decimal { if d.exp >= -places { @@ -944,6 +944,55 @@ func (d Decimal) RoundFloor(places int32) Decimal { return rescaled } +// RoundUp rounds the decimal towards +infinity. +// +// Example: +// +// 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" +// +func (d Decimal) RoundUp(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + + if d.value.Sign() > 0 { + rescaled.value.Add(rescaled.value, oneInt) + } else if d.value.Sign() < 0 { + rescaled.value.Sub(rescaled.value, oneInt) + } + + return rescaled +} + +// RoundDown rounds the decimal towards -infinity. +// +// Example: +// +// 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" +// +func (d Decimal) RoundDown(places int32) Decimal { + if d.exp >= -places { + return d + } + + rescaled := d.rescale(-places) + if d.Equal(rescaled) { + return d + } + return rescaled +} + // RoundBank rounds the decimal to places decimal places. // If the final digit to round is equidistant from the nearest two integers the // rounded value is taken as the even number diff --git a/decimal_test.go b/decimal_test.go index 40f27cc1..36677548 100644 --- a/decimal_test.go +++ b/decimal_test.go @@ -1266,6 +1266,188 @@ func TestDecimal_RoundFloorAndStringFixed(t *testing.T) { } } +func TestDecimal_RoundUpAndStringFixed(t *testing.T) { + type testData struct { + input string + places int32 + expected string + expectedFixed string + } + tests := []testData{ + {"1.454", 0, "2", ""}, + {"1.454", 1, "1.5", ""}, + {"1.454", 2, "1.46", ""}, + {"1.454", 3, "1.454", ""}, + {"1.454", 4, "1.454", "1.4540"}, + {"1.454", 5, "1.454", "1.45400"}, + {"1.554", 0, "2", ""}, + {"1.554", 1, "1.6", ""}, + {"1.554", 2, "1.56", ""}, + {"0.554", 0, "1", ""}, + {"0.454", 0, "1", ""}, + {"0.454", 5, "0.454", "0.45400"}, + {"0", 0, "0", ""}, + {"0", 1, "0", "0.0"}, + {"0", 2, "0", "0.00"}, + {"0", -1, "0", ""}, + {"5", 2, "5", "5.00"}, + {"5", 1, "5", "5.0"}, + {"5", 0, "5", ""}, + {"500", 2, "500", "500.00"}, + {"500", -2, "500", ""}, + {"545", -1, "550", ""}, + {"545", -2, "600", ""}, + {"545", -3, "1000", ""}, + {"545", -4, "10000", ""}, + {"499", -3, "1000", ""}, + {"499", -4, "10000", ""}, + {"1.1001", 2, "1.11", ""}, + {"-1.1001", 2, "-1.11", ""}, + {"-1.454", 0, "-2", ""}, + {"-1.454", 1, "-1.5", ""}, + {"-1.454", 2, "-1.46", ""}, + {"-1.454", 3, "-1.454", ""}, + {"-1.454", 4, "-1.454", "-1.4540"}, + {"-1.454", 5, "-1.454", "-1.45400"}, + {"-1.554", 0, "-2", ""}, + {"-1.554", 1, "-1.6", ""}, + {"-1.554", 2, "-1.56", ""}, + {"-0.554", 0, "-1", ""}, + {"-0.454", 0, "-1", ""}, + {"-0.454", 5, "-0.454", "-0.45400"}, + {"-5", 2, "-5", "-5.00"}, + {"-5", 1, "-5", "-5.0"}, + {"-5", 0, "-5", ""}, + {"-500", 2, "-500", "-500.00"}, + {"-500", -2, "-500", ""}, + {"-545", -1, "-550", ""}, + {"-545", -2, "-600", ""}, + {"-545", -3, "-1000", ""}, + {"-545", -4, "-10000", ""}, + {"-499", -3, "-1000", ""}, + {"-499", -4, "-10000", ""}, + } + + for _, test := range tests { + d, err := NewFromString(test.input) + if err != nil { + t.Fatal(err) + } + + // test Round + expected, err := NewFromString(test.expected) + if err != nil { + t.Fatal(err) + } + got := d.RoundUp(test.places) + if !got.Equal(expected) { + t.Errorf("Rounding up %s to %d places, got %s, expected %s", + d, test.places, got, expected) + } + + // test StringFixed + if test.expectedFixed == "" { + test.expectedFixed = test.expected + } + gotStr := got.StringFixed(test.places) + if gotStr != test.expectedFixed { + t.Errorf("(%s).StringFixed(%d): got %s, expected %s", + d, test.places, gotStr, test.expectedFixed) + } + } +} + +func TestDecimal_RoundDownAndStringFixed(t *testing.T) { + type testData struct { + input string + places int32 + expected string + expectedFixed string + } + tests := []testData{ + {"1.454", 0, "1", ""}, + {"1.454", 1, "1.4", ""}, + {"1.454", 2, "1.45", ""}, + {"1.454", 3, "1.454", ""}, + {"1.454", 4, "1.454", "1.4540"}, + {"1.454", 5, "1.454", "1.45400"}, + {"1.554", 0, "1", ""}, + {"1.554", 1, "1.5", ""}, + {"1.554", 2, "1.55", ""}, + {"0.554", 0, "0", ""}, + {"0.454", 0, "0", ""}, + {"0.454", 5, "0.454", "0.45400"}, + {"0", 0, "0", ""}, + {"0", 1, "0", "0.0"}, + {"0", 2, "0", "0.00"}, + {"0", -1, "0", ""}, + {"5", 2, "5", "5.00"}, + {"5", 1, "5", "5.0"}, + {"5", 0, "5", ""}, + {"500", 2, "500", "500.00"}, + {"500", -2, "500", ""}, + {"545", -1, "540", ""}, + {"545", -2, "500", ""}, + {"545", -3, "0", ""}, + {"545", -4, "0", ""}, + {"499", -3, "0", ""}, + {"499", -4, "0", ""}, + {"1.1001", 2, "1.10", ""}, + {"-1.1001", 2, "-1.10", ""}, + {"-1.454", 0, "-1", ""}, + {"-1.454", 1, "-1.4", ""}, + {"-1.454", 2, "-1.45", ""}, + {"-1.454", 3, "-1.454", ""}, + {"-1.454", 4, "-1.454", "-1.4540"}, + {"-1.454", 5, "-1.454", "-1.45400"}, + {"-1.554", 0, "-1", ""}, + {"-1.554", 1, "-1.5", ""}, + {"-1.554", 2, "-1.55", ""}, + {"-0.554", 0, "0", ""}, + {"-0.454", 0, "0", ""}, + {"-0.454", 5, "-0.454", "-0.45400"}, + {"-5", 2, "-5", "-5.00"}, + {"-5", 1, "-5", "-5.0"}, + {"-5", 0, "-5", ""}, + {"-500", 2, "-500", "-500.00"}, + {"-500", -2, "-500", ""}, + {"-545", -1, "-540", ""}, + {"-545", -2, "-500", ""}, + {"-545", -3, "0", ""}, + {"-545", -4, "0", ""}, + {"-499", -3, "0", ""}, + {"-499", -4, "0", ""}, + } + + for _, test := range tests { + d, err := NewFromString(test.input) + if err != nil { + t.Fatal(err) + } + + // test Round + expected, err := NewFromString(test.expected) + if err != nil { + t.Fatal(err) + } + got := d.RoundDown(test.places) + if !got.Equal(expected) { + t.Errorf("Rounding down %s to %d places, got %s, expected %s", + d, test.places, got, expected) + } + + // test StringFixed + if test.expectedFixed == "" { + test.expectedFixed = test.expected + } + gotStr := got.StringFixed(test.places) + if gotStr != test.expectedFixed { + t.Errorf("(%s).StringFixed(%d): got %s, expected %s", + d, test.places, gotStr, test.expectedFixed) + } + } +} + func TestDecimal_BankRoundAndStringFixed(t *testing.T) { type testData struct { input string From b28c6083d0901cc9219ed6ea6507321d3275773a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Drake=20=28V=C5=A9=20Long=29?= Date: Fri, 12 Mar 2021 10:22:52 +0700 Subject: [PATCH 3/3] Modify the docs of RoundUp and RoundDown --- decimal.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/decimal.go b/decimal.go index 6a0040d4..db4efc6f 100644 --- a/decimal.go +++ b/decimal.go @@ -944,7 +944,7 @@ func (d Decimal) RoundFloor(places int32) Decimal { return rescaled } -// RoundUp rounds the decimal towards +infinity. +// RoundUp rounds the decimal away from zero. // // Example: // @@ -972,7 +972,7 @@ func (d Decimal) RoundUp(places int32) Decimal { return rescaled } -// RoundDown rounds the decimal towards -infinity. +// RoundDown rounds the decimal towards zero. // // Example: //