mirror of
https://github.com/shopspring/decimal.git
synced 2024-11-22 12:30:49 +01:00
Implement RoundUp and RoundDown methods (#196)
* Implement RoundUp and RoundDown methods
This commit is contained in:
parent
66332b32a9
commit
8bd41ac55d
2 changed files with 222 additions and 2 deletions
42
decimal.go
42
decimal.go
|
@ -870,6 +870,48 @@ func (d Decimal) Round(places int32) Decimal {
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RoundUp rounds the decimal towards +infinity.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// NewFromFloat(545).RoundUp(-2).String() // output: "600"
|
||||||
|
// 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.value.Sign() > 0 {
|
||||||
|
rescaled.value.Add(rescaled.value, oneInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rescaled
|
||||||
|
}
|
||||||
|
|
||||||
|
// RoundDown rounds the decimal towards -infinity.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// NewFromFloat(545).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.value.Sign() < 0 {
|
||||||
|
rescaled.value.Sub(rescaled.value, oneInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rescaled
|
||||||
|
}
|
||||||
|
|
||||||
// RoundBank rounds the decimal to places decimal places.
|
// RoundBank rounds the decimal to places decimal places.
|
||||||
// If the final digit to round is equidistant from the nearest two integers the
|
// If the final digit to round is equidistant from the nearest two integers the
|
||||||
// rounded value is taken as the even number
|
// rounded value is taken as the even number
|
||||||
|
|
182
decimal_test.go
182
decimal_test.go
|
@ -968,13 +968,13 @@ func TestDecimal_RoundAndStringFixed(t *testing.T) {
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
d, err := NewFromString(test.input)
|
d, err := NewFromString(test.input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test Round
|
// test Round
|
||||||
expected, err := NewFromString(test.expected)
|
expected, err := NewFromString(test.expected)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
got := d.Round(test.places)
|
got := d.Round(test.places)
|
||||||
if !got.Equal(expected) {
|
if !got.Equal(expected) {
|
||||||
|
@ -994,6 +994,184 @@ func TestDecimal_RoundAndStringFixed(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"},
|
||||||
|
{"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.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"},
|
||||||
|
{"-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.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"},
|
||||||
|
{"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.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"},
|
||||||
|
{"-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.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) {
|
func TestDecimal_BankRoundAndStringFixed(t *testing.T) {
|
||||||
type testData struct {
|
type testData struct {
|
||||||
input string
|
input string
|
||||||
|
|
Loading…
Reference in a new issue