Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: Sortable Decimal Bytes #5360

Merged
merged 10 commits into from
Dec 5, 2019
19 changes: 19 additions & 0 deletions types/decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,25 @@ func (d Dec) Ceil() Dec {

//___________________________________________________________________________________

// ValidSortableDec ensures that a Dec is within the sortable bounds,
// a Dec can't have a precision of less than 10^-18.
// Max sortable decimal was set to the reciprocal of SmallestDec.
func ValidSortableDec(dec Dec) bool {
return dec.LTE(OneDec().Quo(SmallestDec()))
}

// SortableDecBytes returns a byte slice representation of a Dec that can be sorted.
// Left and right pads with 0s so there are 18 digits to left and right of the decimal point.
// For this reason, there is a maximum and minimum value for this, enforced by ValidSortableDec.
func SortableDecBytes(dec Dec) []byte {
if !ValidSortableDec(dec) {
panic("dec must be within bounds")
}
return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.String()))
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
}

//___________________________________________________________________________________

// reuse nil values
var (
nilAmino string
Expand Down
19 changes: 19 additions & 0 deletions types/decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,22 @@ func TestApproxSqrt(t *testing.T) {
require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input)
}
}

func TestDecSortableBytes(t *testing.T) {
tests := []struct {
d Dec
want []byte
}{
{NewDec(0), []byte("000000000000000000.000000000000000000")},
{NewDec(1), []byte("000000000000000001.000000000000000000")},
{NewDec(10), []byte("000000000000000010.000000000000000000")},
{NewDec(12340), []byte("000000000000012340.000000000000000000")},
{NewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")},
{NewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")},
{NewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")},
{NewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")},
}
for tcIndex, tc := range tests {
assert.Equal(t, tc.want, SortableDecBytes(tc.d), "bad String(), index: %v", tcIndex)
}
}