Fix TruncateDecimal (#3913)

This commit is contained in:
Alexander Bezobchuk 2019-03-16 16:14:37 -07:00 committed by GitHub
parent 3d2886dc49
commit 5f92fef4b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 53 additions and 12 deletions

View File

@ -0,0 +1,2 @@
#3870 Fix DecCoins#TruncateDecimal to never return zero coins in
either the truncated coins or the change coins.

View File

@ -114,7 +114,8 @@ func (coin DecCoin) Sub(coinB DecCoin) DecCoin {
return DecCoin{coin.Denom, coin.Amount.Sub(coinB.Amount)}
}
// return the decimal coins with trunctated decimals, and return the change
// TruncateDecimal returns a Coin with a truncated decimal and a DecCoin for the
// change. Note, the change may be zero.
func (coin DecCoin) TruncateDecimal() (Coin, DecCoin) {
truncated := coin.Amount.TruncateInt()
change := coin.Amount.Sub(truncated.ToDec())
@ -171,20 +172,20 @@ func (coins DecCoins) String() string {
}
// TruncateDecimal returns the coins with truncated decimals and returns the
// change.
func (coins DecCoins) TruncateDecimal() (Coins, DecCoins) {
changeSum := DecCoins{}
out := make(Coins, len(coins))
for i, coin := range coins {
// change. Note, it will not return any zero-amount coins in either the truncated or
// change coins.
func (coins DecCoins) TruncateDecimal() (truncatedCoins Coins, changeCoins DecCoins) {
for _, coin := range coins {
truncated, change := coin.TruncateDecimal()
out[i] = truncated
if !truncated.IsZero() {
truncatedCoins = truncatedCoins.Add(Coins{truncated})
}
if !change.IsZero() {
changeSum = changeSum.Add(DecCoins{change})
changeCoins = changeCoins.Add(DecCoins{change})
}
}
return out, changeSum
return truncatedCoins, changeCoins
}
// Add adds two sets of DecCoins.

View File

@ -253,6 +253,40 @@ func TestDecCoinsIntersect(t *testing.T) {
require.NoError(t, err, "unexpected parse error in %v", i)
require.True(t, in1.Intersect(in2).IsEqual(exr), "in1.cap(in2) != exr in %v", i)
// require.Equal(t, tc.expectedResult, in1.Intersect(in2).String(), "in1.cap(in2) != exr in %v", i)
}
}
func TestDecCoinsTruncateDecimal(t *testing.T) {
decCoinA := NewDecCoinFromDec("bar", MustNewDecFromStr("5.41"))
decCoinB := NewDecCoinFromDec("foo", MustNewDecFromStr("6.00"))
testCases := []struct {
input DecCoins
truncatedCoins Coins
changeCoins DecCoins
}{
{DecCoins{}, Coins(nil), DecCoins(nil)},
{
DecCoins{decCoinA, decCoinB},
Coins{NewInt64Coin(decCoinA.Denom, 5), NewInt64Coin(decCoinB.Denom, 6)},
DecCoins{NewDecCoinFromDec(decCoinA.Denom, MustNewDecFromStr("0.41"))},
},
{
DecCoins{decCoinB},
Coins{NewInt64Coin(decCoinB.Denom, 6)},
DecCoins(nil),
},
}
for i, tc := range testCases {
truncatedCoins, changeCoins := tc.input.TruncateDecimal()
require.Equal(
t, tc.truncatedCoins, truncatedCoins,
"unexpected truncated coins; tc #%d, input: %s", i, tc.input,
)
require.Equal(
t, tc.changeCoins, changeCoins,
"unexpected change coins; tc #%d, input: %s", i, tc.input,
)
}
}

View File

@ -332,6 +332,10 @@ func (d Dec) Format(s fmt.State, verb rune) {
}
func (d Dec) String() string {
if d.Int == nil {
return d.Int.String()
}
isNeg := d.IsNegative()
if d.IsNegative() {
d = d.Neg()
@ -348,7 +352,6 @@ func (d Dec) String() string {
// TODO: Remove trailing zeros
// case 1, purely decimal
if inputSize <= Precision {
bzStr = make([]byte, Precision+2)
// 0. prefix
@ -377,6 +380,7 @@ func (d Dec) String() string {
if isNeg {
return "-" + string(bzStr)
}
return string(bzStr)
}