Modify Rounding methods (#220)

* Change function name from RoundUp -> RoundCeil, RoundDown -> RoundFloor
* Add a new RoundUp and RoundDown methods
* Modify the docs of RoundUp and RoundDown
This commit is contained in:
Vu Long (Drake) 2021-03-15 04:09:56 +07:00 committed by GitHub
parent 9328d16578
commit f77bb07828
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 242 additions and 11 deletions

View file

@ -892,7 +892,59 @@ func (d Decimal) Round(places int32) Decimal {
return ret return ret
} }
// RoundUp rounds the decimal towards +infinity. // RoundCeil rounds the decimal towards +infinity.
//
// Example:
//
// 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.5"
//
func (d Decimal) RoundCeil(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)
}
return rescaled
}
// RoundFloor rounds the decimal towards -infinity.
//
// Example:
//
// 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.4"
//
func (d Decimal) RoundFloor(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.Sub(rescaled.value, oneInt)
}
return rescaled
}
// RoundUp rounds the decimal away from zero.
// //
// Example: // Example:
// //
@ -913,12 +965,14 @@ func (d Decimal) RoundUp(places int32) Decimal {
if d.value.Sign() > 0 { if d.value.Sign() > 0 {
rescaled.value.Add(rescaled.value, oneInt) rescaled.value.Add(rescaled.value, oneInt)
} else if d.value.Sign() < 0 {
rescaled.value.Sub(rescaled.value, oneInt)
} }
return rescaled return rescaled
} }
// RoundDown rounds the decimal towards -infinity. // RoundDown rounds the decimal towards zero.
// //
// Example: // Example:
// //
@ -936,11 +990,6 @@ func (d Decimal) RoundDown(places int32) Decimal {
if d.Equal(rescaled) { if d.Equal(rescaled) {
return d return d
} }
if d.value.Sign() < 0 {
rescaled.value.Sub(rescaled.value, oneInt)
}
return rescaled return rescaled
} }

View file

@ -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 { type testData struct {
input string input string
places int32 places int32
@ -1157,9 +1157,9 @@ func TestDecimal_RoundUpAndStringFixed(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
got := d.RoundUp(test.places) got := d.RoundCeil(test.places)
if !got.Equal(expected) { 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) 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 { type testData struct {
input string input string
places int32 places int32
@ -1237,6 +1237,188 @@ func TestDecimal_RoundDownAndStringFixed(t *testing.T) {
{"-499", -4, "-10000", ""}, {"-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.RoundFloor(test.places)
if !got.Equal(expected) {
t.Errorf("Rounding floor %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_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 { for _, test := range tests {
d, err := NewFromString(test.input) d, err := NewFromString(test.input)
if err != nil { if err != nil {