From 520060dd7f4121f333562503c9a74cb3959395ef Mon Sep 17 00:00:00 2001 From: Amaury M <1293565+amaurym@users.noreply.github.com> Date: Tue, 19 Jul 2022 15:47:45 +0200 Subject: [PATCH 1/6] refactor: Move sdk.Dec to math package --- go.mod | 1 + math/dec.go | 894 +++++++++++++++++ .../dec_internal_test.go | 11 +- math/dec_test.go | 621 ++++++++++++ math/go.mod | 6 +- math/go.sum | 4 + types/decimal.go | 895 ------------------ types/decimal_test.go | 621 ------------ types/math.go | 33 + 9 files changed, 1564 insertions(+), 1522 deletions(-) create mode 100644 math/dec.go rename types/decimal_internal_test.go => math/dec_internal_test.go (92%) create mode 100644 math/dec_test.go delete mode 100644 types/decimal_test.go diff --git a/go.mod b/go.mod index ed8f5ca1f6f8..33ff9da0b118 100644 --- a/go.mod +++ b/go.mod @@ -283,6 +283,7 @@ replace ( cosmossdk.io/api => ./api cosmossdk.io/core => ./core cosmossdk.io/depinject => ./depinject + cosmossdk.io/math => ./math github.com/cosmos/cosmos-sdk/db => ./db github.com/cosmos/cosmos-sdk/store/tools/ics23 => ./store/tools/ics23 diff --git a/math/dec.go b/math/dec.go new file mode 100644 index 000000000000..e4239102bd65 --- /dev/null +++ b/math/dec.go @@ -0,0 +1,894 @@ +package math + +import ( + "encoding/json" + "errors" + "fmt" + "math/big" + "strconv" + "strings" + "testing" +) + +// NOTE: never use new(Dec) or else we will panic unmarshalling into the +// nil embedded big.Int +type Dec struct { + i *big.Int +} + +const ( + // number of decimal places + Precision = 18 + + // bits required to represent the above precision + // Ceiling[Log2[10^Precision - 1]] + DecimalPrecisionBits = 60 + + // decimalTruncateBits is the minimum number of bits removed + // by a truncate operation. It is equal to + // Floor[Log2[10^Precision - 1]]. + decimalTruncateBits = DecimalPrecisionBits - 1 + + maxDecBitLen = MaxBitLen + decimalTruncateBits + + // max number of iterations in ApproxRoot function + maxApproxRootIterations = 300 +) + +var ( + precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) + fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) + precisionMultipliers []*big.Int + zeroInt = big.NewInt(0) + oneInt = big.NewInt(1) + tenInt = big.NewInt(10) +) + +// Decimal errors +var ( + ErrEmptyDecimalStr = errors.New("decimal string cannot be empty") + ErrInvalidDecimalLength = errors.New("invalid decimal length") + ErrInvalidDecimalStr = errors.New("invalid decimal string") +) + +// Set precision multipliers +func init() { + precisionMultipliers = make([]*big.Int, Precision+1) + for i := 0; i <= Precision; i++ { + precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) + } +} + +func precisionInt() *big.Int { + return new(big.Int).Set(precisionReuse) +} + +func ZeroDec() Dec { return Dec{new(big.Int).Set(zeroInt)} } +func OneDec() Dec { return Dec{precisionInt()} } +func SmallestDec() Dec { return Dec{new(big.Int).Set(oneInt)} } + +// calculate the precision multiplier +func calcPrecisionMultiplier(prec int64) *big.Int { + if prec > Precision { + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) + } + zerosToAdd := Precision - prec + multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) + return multiplier +} + +// get the precision multiplier, do not mutate result +func precisionMultiplier(prec int64) *big.Int { + if prec > Precision { + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) + } + return precisionMultipliers[prec] +} + +// create a new Dec from integer assuming whole number +func NewDec(i int64) Dec { + return NewDecWithPrec(i, 0) +} + +// create a new Dec from integer with decimal place at prec +// CONTRACT: prec <= Precision +func NewDecWithPrec(i, prec int64) Dec { + return Dec{ + new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), + } +} + +// create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func NewDecFromBigInt(i *big.Int) Dec { + return NewDecFromBigIntWithPrec(i, 0) +} + +// create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func NewDecFromBigIntWithPrec(i *big.Int, prec int64) Dec { + return Dec{ + new(big.Int).Mul(i, precisionMultiplier(prec)), + } +} + +// create a new Dec from big integer assuming whole numbers +// CONTRACT: prec <= Precision +func NewDecFromInt(i Int) Dec { + return NewDecFromIntWithPrec(i, 0) +} + +// create a new Dec from big integer with decimal place at prec +// CONTRACT: prec <= Precision +func NewDecFromIntWithPrec(i Int, prec int64) Dec { + return Dec{ + new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), + } +} + +// create a decimal from an input decimal string. +// valid must come in the form: +// (-) whole integers (.) decimal integers +// examples of acceptable input include: +// -123.456 +// 456.7890 +// 345 +// -456789 +// +// NOTE - An error will return if more decimal places +// are provided in the string than the constant Precision. +// +// CONTRACT - This function does not mutate the input str. +func NewDecFromStr(str string) (Dec, error) { + if len(str) == 0 { + return Dec{}, fmt.Errorf("%s: %w", str, ErrEmptyDecimalStr) + } + + // first extract any negative symbol + neg := false + if str[0] == '-' { + neg = true + str = str[1:] + } + + if len(str) == 0 { + return Dec{}, fmt.Errorf("%s: %w", str, ErrEmptyDecimalStr) + } + + strs := strings.Split(str, ".") + lenDecs := 0 + combinedStr := strs[0] + + if len(strs) == 2 { // has a decimal place + lenDecs = len(strs[1]) + if lenDecs == 0 || len(combinedStr) == 0 { + return Dec{}, ErrInvalidDecimalLength + } + combinedStr += strs[1] + } else if len(strs) > 2 { + return Dec{}, ErrInvalidDecimalStr + } + + if lenDecs > Precision { + return Dec{}, fmt.Errorf("value '%s' exceeds max precision by %d decimal places: max precision %d", str, Precision-lenDecs, Precision) + } + + // add some extra zero's to correct to the Precision factor + zerosToAdd := Precision - lenDecs + zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "") + combinedStr += zeros + + combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 + if !ok { + return Dec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr) + } + if combined.BitLen() > maxDecBitLen { + return Dec{}, fmt.Errorf("decimal '%s' out of range; bitLen: got %d, max %d", str, combined.BitLen(), maxDecBitLen) + } + if neg { + combined = new(big.Int).Neg(combined) + } + + return Dec{combined}, nil +} + +// Decimal from string, panic on error +func MustNewDecFromStr(s string) Dec { + dec, err := NewDecFromStr(s) + if err != nil { + panic(err) + } + return dec +} + +func (d Dec) IsNil() bool { return d.i == nil } // is decimal nil +func (d Dec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero +func (d Dec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative +func (d Dec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive +func (d Dec) Equal(d2 Dec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals +func (d Dec) GT(d2 Dec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than +func (d Dec) GTE(d2 Dec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal +func (d Dec) LT(d2 Dec) bool { return (d.i).Cmp(d2.i) < 0 } // less than +func (d Dec) LTE(d2 Dec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal +func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.i)} } // reverse the decimal sign +func (d Dec) NegMut() Dec { d.i.Neg(d.i); return d } // reverse the decimal sign, mutable +func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.i)} } // absolute value +func (d Dec) Set(d2 Dec) Dec { d.i.Set(d2.i); return d } // set to existing dec value +func (d Dec) Clone() Dec { return Dec{new(big.Int).Set(d.i)} } // clone new dec + +// BigInt returns a copy of the underlying big.Int. +func (d Dec) BigInt() *big.Int { + if d.IsNil() { + return nil + } + + cp := new(big.Int) + return cp.Set(d.i) +} + +func (d Dec) ImmutOp(op func(Dec, Dec) Dec, d2 Dec) Dec { + return op(d.Clone(), d2) +} + +func (d Dec) ImmutOpInt(op func(Dec, Int) Dec, d2 Int) Dec { + return op(d.Clone(), d2) +} + +func (d Dec) ImmutOpInt64(op func(Dec, int64) Dec, d2 int64) Dec { + // TODO: use already allocated operand bigint to avoid + // newint each time, add mutex for race condition + // Issue: https://github.com/cosmos/cosmos-sdk/issues/11166 + return op(d.Clone(), d2) +} + +func (d Dec) SetInt64(i int64) Dec { + d.i.SetInt64(i) + d.i.Mul(d.i, precisionReuse) + return d +} + +// addition +func (d Dec) Add(d2 Dec) Dec { + return d.ImmutOp(Dec.AddMut, d2) +} + +// mutable addition +func (d Dec) AddMut(d2 Dec) Dec { + d.i.Add(d.i, d2.i) + + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// subtraction +func (d Dec) Sub(d2 Dec) Dec { + return d.ImmutOp(Dec.SubMut, d2) +} + +// mutable subtraction +func (d Dec) SubMut(d2 Dec) Dec { + d.i.Sub(d.i, d2.i) + + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// multiplication +func (d Dec) Mul(d2 Dec) Dec { + return d.ImmutOp(Dec.MulMut, d2) +} + +// mutable multiplication +func (d Dec) MulMut(d2 Dec) Dec { + d.i.Mul(d.i, d2.i) + chopped := chopPrecisionAndRound(d.i) + + if chopped.BitLen() > maxDecBitLen { + panic("Int overflow") + } + *d.i = *chopped + return d +} + +// multiplication truncate +func (d Dec) MulTruncate(d2 Dec) Dec { + return d.ImmutOp(Dec.MulTruncateMut, d2) +} + +// mutable multiplication truncage +func (d Dec) MulTruncateMut(d2 Dec) Dec { + d.i.Mul(d.i, d2.i) + chopPrecisionAndTruncate(d.i) + + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// multiplication +func (d Dec) MulInt(i Int) Dec { + return d.ImmutOpInt(Dec.MulIntMut, i) +} + +func (d Dec) MulIntMut(i Int) Dec { + d.i.Mul(d.i, i.BigInt()) + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// MulInt64 - multiplication with int64 +func (d Dec) MulInt64(i int64) Dec { + return d.ImmutOpInt64(Dec.MulInt64Mut, i) +} + +func (d Dec) MulInt64Mut(i int64) Dec { + d.i.Mul(d.i, big.NewInt(i)) + + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// quotient +func (d Dec) Quo(d2 Dec) Dec { + return d.ImmutOp(Dec.QuoMut, d2) +} + +// mutable quotient +func (d Dec) QuoMut(d2 Dec) Dec { + // multiply precision twice + d.i.Mul(d.i, precisionReuse) + d.i.Mul(d.i, precisionReuse) + d.i.Quo(d.i, d2.i) + + chopPrecisionAndRound(d.i) + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// quotient truncate +func (d Dec) QuoTruncate(d2 Dec) Dec { + return d.ImmutOp(Dec.QuoTruncateMut, d2) +} + +// mutable quotient truncate +func (d Dec) QuoTruncateMut(d2 Dec) Dec { + // multiply precision twice + d.i.Mul(d.i, precisionReuse) + d.i.Mul(d.i, precisionReuse) + d.i.Quo(d.i, d2.i) + + chopPrecisionAndTruncate(d.i) + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// quotient, round up +func (d Dec) QuoRoundUp(d2 Dec) Dec { + return d.ImmutOp(Dec.QuoRoundupMut, d2) +} + +// mutable quotient, round up +func (d Dec) QuoRoundupMut(d2 Dec) Dec { + // multiply precision twice + d.i.Mul(d.i, precisionReuse) + d.i.Mul(d.i, precisionReuse) + d.i.Quo(d.i, d2.i) + + chopPrecisionAndRoundUp(d.i) + if d.i.BitLen() > maxDecBitLen { + panic("Int overflow") + } + return d +} + +// quotient +func (d Dec) QuoInt(i Int) Dec { + return d.ImmutOpInt(Dec.QuoIntMut, i) +} + +func (d Dec) QuoIntMut(i Int) Dec { + d.i.Quo(d.i, i.BigInt()) + return d +} + +// QuoInt64 - quotient with int64 +func (d Dec) QuoInt64(i int64) Dec { + return d.ImmutOpInt64(Dec.QuoInt64Mut, i) +} + +func (d Dec) QuoInt64Mut(i int64) Dec { + d.i.Quo(d.i, big.NewInt(i)) + return d +} + +// ApproxRoot returns an approximate estimation of a Dec's positive real nth root +// using Newton's method (where n is positive). The algorithm starts with some guess and +// computes the sequence of improved guesses until an answer converges to an +// approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. +// A maximum number of 100 iterations is used a backup boundary condition for +// cases where the answer never converges enough to satisfy the main condition. +func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + err, ok = r.(error) + if !ok { + err = errors.New("out of bounds") + } + } + }() + + if d.IsNegative() { + absRoot, err := d.Neg().ApproxRoot(root) + return absRoot.NegMut(), err + } + + if root == 1 || d.IsZero() || d.Equal(OneDec()) { + return d, nil + } + + if root == 0 { + return OneDec(), nil + } + + guess, delta := OneDec(), OneDec() + + for iter := 0; delta.Abs().GT(SmallestDec()) && iter < maxApproxRootIterations; iter++ { + prev := guess.Power(root - 1) + if prev.IsZero() { + prev = SmallestDec() + } + delta.Set(d).QuoMut(prev) + delta.SubMut(guess) + delta.QuoInt64Mut(int64(root)) + + guess.AddMut(delta) + } + + return guess, nil +} + +// Power returns a the result of raising to a positive integer power +func (d Dec) Power(power uint64) Dec { + res := Dec{new(big.Int).Set(d.i)} + return res.PowerMut(power) +} + +func (d Dec) PowerMut(power uint64) Dec { + if power == 0 { + d.SetInt64(1) + return d + } + tmp := OneDec() + + for i := power; i > 1; { + if i%2 != 0 { + tmp.MulMut(d) + } + i /= 2 + d.MulMut(d) + } + + return d.MulMut(tmp) +} + +// ApproxSqrt is a wrapper around ApproxRoot for the common special case +// of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. +func (d Dec) ApproxSqrt() (Dec, error) { + return d.ApproxRoot(2) +} + +// is integer, e.g. decimals are zero +func (d Dec) IsInteger() bool { + return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 +} + +// format decimal state +func (d Dec) Format(s fmt.State, verb rune) { + _, err := s.Write([]byte(d.String())) + if err != nil { + panic(err) + } +} + +func (d Dec) String() string { + if d.i == nil { + return d.i.String() + } + + isNeg := d.IsNegative() + + if isNeg { + d = d.Neg() + } + + bzInt, err := d.i.MarshalText() + if err != nil { + return "" + } + inputSize := len(bzInt) + + var bzStr []byte + + // TODO: Remove trailing zeros + // case 1, purely decimal + if inputSize <= Precision { + bzStr = make([]byte, Precision+2) + + // 0. prefix + bzStr[0] = byte('0') + bzStr[1] = byte('.') + + // set relevant digits to 0 + for i := 0; i < Precision-inputSize; i++ { + bzStr[i+2] = byte('0') + } + + // set final digits + copy(bzStr[2+(Precision-inputSize):], bzInt) + } else { + // inputSize + 1 to account for the decimal point that is being added + bzStr = make([]byte, inputSize+1) + decPointPlace := inputSize - Precision + + copy(bzStr, bzInt[:decPointPlace]) // pre-decimal digits + bzStr[decPointPlace] = byte('.') // decimal point + copy(bzStr[decPointPlace+1:], bzInt[decPointPlace:]) // post-decimal digits + } + + if isNeg { + return "-" + string(bzStr) + } + + return string(bzStr) +} + +// Float64 returns the float64 representation of a Dec. +// Will return the error if the conversion failed. +func (d Dec) Float64() (float64, error) { + return strconv.ParseFloat(d.String(), 64) +} + +// MustFloat64 returns the float64 representation of a Dec. +// Would panic if the conversion failed. +func (d Dec) MustFloat64() float64 { + if value, err := strconv.ParseFloat(d.String(), 64); err != nil { + panic(err) + } else { + return value + } +} + +// ____ +// __| |__ "chop 'em +// ` \ round!" +// ___|| ~ _ -bankers +// | | __ +// | | | __|__|__ +// |_____: / | $$$ | +// |________| + +// Remove a Precision amount of rightmost digits and perform bankers rounding +// on the remainder (gaussian rounding) on the digits which have been removed. +// +// Mutates the input. Use the non-mutative version if that is undesired +func chopPrecisionAndRound(d *big.Int) *big.Int { + // remove the negative and add it back when returning + if d.Sign() == -1 { + // make d positive, compute chopped value, and then un-mutate d + d = d.Neg(d) + d = chopPrecisionAndRound(d) + d = d.Neg(d) + return d + } + + // get the truncated quotient and remainder + quo, rem := d, big.NewInt(0) + quo, rem = quo.QuoRem(d, precisionReuse, rem) + + if rem.Sign() == 0 { // remainder is zero + return quo + } + + switch rem.Cmp(fivePrecision) { + case -1: + return quo + case 1: + return quo.Add(quo, oneInt) + default: // bankers rounding must take place + // always round to an even number + if quo.Bit(0) == 0 { + return quo + } + return quo.Add(quo, oneInt) + } +} + +func chopPrecisionAndRoundUp(d *big.Int) *big.Int { + // remove the negative and add it back when returning + if d.Sign() == -1 { + // make d positive, compute chopped value, and then un-mutate d + d = d.Neg(d) + // truncate since d is negative... + chopPrecisionAndTruncate(d) + d = d.Neg(d) + return d + } + + // get the truncated quotient and remainder + quo, rem := d, big.NewInt(0) + quo, rem = quo.QuoRem(d, precisionReuse, rem) + + if rem.Sign() == 0 { // remainder is zero + return quo + } + + return quo.Add(quo, oneInt) +} + +func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { + tmp := new(big.Int).Set(d) + return chopPrecisionAndRound(tmp) +} + +// RoundInt64 rounds the decimal using bankers rounding +func (d Dec) RoundInt64() int64 { + chopped := chopPrecisionAndRoundNonMutative(d.i) + if !chopped.IsInt64() { + panic("Int64() out of bound") + } + return chopped.Int64() +} + +// RoundInt round the decimal using bankers rounding +func (d Dec) RoundInt() Int { + return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.i)) +} + +// chopPrecisionAndTruncate is similar to chopPrecisionAndRound, +// but always rounds down. It does not mutate the input. +func chopPrecisionAndTruncate(d *big.Int) { + d.Quo(d, precisionReuse) +} + +func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { + tmp := new(big.Int).Set(d) + chopPrecisionAndTruncate(tmp) + return tmp +} + +// TruncateInt64 truncates the decimals from the number and returns an int64 +func (d Dec) TruncateInt64() int64 { + chopped := chopPrecisionAndTruncateNonMutative(d.i) + if !chopped.IsInt64() { + panic("Int64() out of bound") + } + return chopped.Int64() +} + +// TruncateInt truncates the decimals from the number and returns an Int +func (d Dec) TruncateInt() Int { + return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) +} + +// TruncateDec truncates the decimals from the number and returns a Dec +func (d Dec) TruncateDec() Dec { + return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) +} + +// Ceil returns the smallest interger value (as a decimal) that is greater than +// or equal to the given decimal. +func (d Dec) Ceil() Dec { + tmp := new(big.Int).Set(d.i) + + quo, rem := tmp, big.NewInt(0) + quo, rem = quo.QuoRem(tmp, precisionReuse, rem) + + // no need to round with a zero remainder regardless of sign + if rem.Cmp(zeroInt) == 0 { + return NewDecFromBigInt(quo) + } + + if rem.Sign() == -1 { + return NewDecFromBigInt(quo) + } + + return NewDecFromBigInt(quo.Add(quo, oneInt)) +} + +// MaxSortableDec is the largest Dec that can be passed into SortableDecBytes() +// Its negative form is the least Dec that can be passed in. +var MaxSortableDec Dec + +func init() { + MaxSortableDec = OneDec().Quo(SmallestDec()) +} + +// 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.Abs().LTE(MaxSortableDec) +} + +// 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") + } + // Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just + // makes its bytes be "max" which comes after all numbers in ASCIIbetical order + if dec.Equal(MaxSortableDec) { + return []byte("max") + } + // For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers. + if dec.Equal(MaxSortableDec.Neg()) { + return []byte("--") + } + // We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers + if dec.IsNegative() { + return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.Abs().String()))...) + } + return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.String())) +} + +// reuse nil values +var nilJSON []byte + +func init() { + empty := new(big.Int) + bz, _ := empty.MarshalText() + nilJSON, _ = json.Marshal(string(bz)) +} + +// MarshalJSON marshals the decimal +func (d Dec) MarshalJSON() ([]byte, error) { + if d.i == nil { + return nilJSON, nil + } + return json.Marshal(d.String()) +} + +// UnmarshalJSON defines custom decoding scheme +func (d *Dec) UnmarshalJSON(bz []byte) error { + if d.i == nil { + d.i = new(big.Int) + } + + var text string + err := json.Unmarshal(bz, &text) + if err != nil { + return err + } + + // TODO: Reuse dec allocation + newDec, err := NewDecFromStr(text) + if err != nil { + return err + } + + d.i = newDec.i + return nil +} + +// MarshalYAML returns the YAML representation. +func (d Dec) MarshalYAML() (interface{}, error) { + return d.String(), nil +} + +// Marshal implements the gogo proto custom type interface. +func (d Dec) Marshal() ([]byte, error) { + if d.i == nil { + d.i = new(big.Int) + } + return d.i.MarshalText() +} + +// MarshalTo implements the gogo proto custom type interface. +func (d *Dec) MarshalTo(data []byte) (n int, err error) { + if d.i == nil { + d.i = new(big.Int) + } + + if d.i.Cmp(zeroInt) == 0 { + copy(data, []byte{0x30}) + return 1, nil + } + + bz, err := d.Marshal() + if err != nil { + return 0, err + } + + copy(data, bz) + return len(bz), nil +} + +// Unmarshal implements the gogo proto custom type interface. +func (d *Dec) Unmarshal(data []byte) error { + if len(data) == 0 { + d = nil + return nil + } + + if d.i == nil { + d.i = new(big.Int) + } + + if err := d.i.UnmarshalText(data); err != nil { + return err + } + + if d.i.BitLen() > maxDecBitLen { + return fmt.Errorf("decimal out of range; got: %d, max: %d", d.i.BitLen(), maxDecBitLen) + } + + return nil +} + +// Size implements the gogo proto custom type interface. +func (d *Dec) Size() int { + bz, _ := d.Marshal() + return len(bz) +} + +// Override Amino binary serialization by proxying to protobuf. +func (d Dec) MarshalAmino() ([]byte, error) { return d.Marshal() } +func (d *Dec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } + +// helpers + +// test if two decimal arrays are equal +func DecsEqual(d1s, d2s []Dec) bool { + if len(d1s) != len(d2s) { + return false + } + + for i, d1 := range d1s { + if !d1.Equal(d2s[i]) { + return false + } + } + return true +} + +// minimum decimal between two +func MinDec(d1, d2 Dec) Dec { + if d1.LT(d2) { + return d1 + } + return d2 +} + +// maximum decimal between two +func MaxDec(d1, d2 Dec) Dec { + if d1.LT(d2) { + return d2 + } + return d1 +} + +// intended to be used with require/assert: require.True(DecEq(...)) +func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, string, string) { + return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String() +} + +func DecApproxEq(t *testing.T, d1 Dec, d2 Dec, tol Dec) (*testing.T, bool, string, string, string) { + diff := d1.Sub(d2).Abs() + return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String() +} diff --git a/types/decimal_internal_test.go b/math/dec_internal_test.go similarity index 92% rename from types/decimal_internal_test.go rename to math/dec_internal_test.go index 6127267853ba..960540735a9f 100644 --- a/types/decimal_internal_test.go +++ b/math/dec_internal_test.go @@ -1,6 +1,7 @@ -package types +package math import ( + "encoding/json" "math/big" "testing" @@ -23,20 +24,20 @@ func (s *decimalInternalTestSuite) TestPrecisionMultiplier() { func (s *decimalInternalTestSuite) TestZeroDeserializationJSON() { d := Dec{new(big.Int)} - err := cdc.UnmarshalJSON([]byte(`"0"`), &d) + err := json.Unmarshal([]byte(`"0"`), &d) s.Require().Nil(err) - err = cdc.UnmarshalJSON([]byte(`"{}"`), &d) + err = json.Unmarshal([]byte(`"{}"`), &d) s.Require().NotNil(err) } func (s *decimalInternalTestSuite) TestSerializationGocodecJSON() { d := MustNewDecFromStr("0.333") - bz, err := cdc.MarshalJSON(d) + bz, err := json.Marshal(d) s.Require().NoError(err) d2 := Dec{new(big.Int)} - err = cdc.UnmarshalJSON(bz, &d2) + err = json.Unmarshal(bz, &d2) s.Require().NoError(err) s.Require().True(d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } diff --git a/math/dec_test.go b/math/dec_test.go new file mode 100644 index 000000000000..024a05bec16a --- /dev/null +++ b/math/dec_test.go @@ -0,0 +1,621 @@ +package math_test + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + "strings" + "testing" + + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "sigs.k8s.io/yaml" + + "cosmossdk.io/math" +) + +type decimalTestSuite struct { + suite.Suite +} + +func TestDecimalTestSuite(t *testing.T) { + suite.Run(t, new(decimalTestSuite)) +} + +func TestDecApproxEq(t *testing.T) { + // d1 = 0.55, d2 = 0.6, tol = 0.1 + d1 := math.NewDecWithPrec(55, 2) + d2 := math.NewDecWithPrec(6, 1) + tol := math.NewDecWithPrec(1, 1) + + require.True(math.DecApproxEq(t, d1, d2, tol)) + + // d1 = 0.55, d2 = 0.6, tol = 1E-5 + d1 = math.NewDecWithPrec(55, 2) + d2 = math.NewDecWithPrec(6, 1) + tol = math.NewDecWithPrec(1, 5) + + require.False(math.DecApproxEq(t, d1, d2, tol)) + + // d1 = 0.6, d2 = 0.61, tol = 0.01 + d1 = math.NewDecWithPrec(6, 1) + d2 = math.NewDecWithPrec(61, 2) + tol = math.NewDecWithPrec(1, 2) + + require.True(math.DecApproxEq(t, d1, d2, tol)) +} + +// create a decimal from a decimal string (ex. "1234.5678") +func (s *decimalTestSuite) mustNewDecFromStr(str string) (d math.Dec) { + d, err := math.NewDecFromStr(str) + s.Require().NoError(err) + + return d +} + +func (s *decimalTestSuite) TestNewDecFromStr() { + largeBigInt, ok := new(big.Int).SetString("3144605511029693144278234343371835", 10) + s.Require().True(ok) + + largerBigInt, ok := new(big.Int).SetString("8888888888888888888888888888888888888888888888888888888888888888888844444440", 10) + s.Require().True(ok) + + largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) + s.Require().True(ok) + + tests := []struct { + decimalStr string + expErr bool + exp math.Dec + }{ + {"", true, math.Dec{}}, + {"0.-75", true, math.Dec{}}, + {"0", false, math.NewDec(0)}, + {"1", false, math.NewDec(1)}, + {"1.1", false, math.NewDecWithPrec(11, 1)}, + {"0.75", false, math.NewDecWithPrec(75, 2)}, + {"0.8", false, math.NewDecWithPrec(8, 1)}, + {"0.11111", false, math.NewDecWithPrec(11111, 5)}, + {"314460551102969.3144278234343371835", true, math.NewDec(3141203149163817869)}, + { + "314460551102969314427823434337.1835718092488231350", + true, math.NewDecFromBigIntWithPrec(largeBigInt, 4), + }, + { + "314460551102969314427823434337.1835", + false, math.NewDecFromBigIntWithPrec(largeBigInt, 4), + }, + {".", true, math.Dec{}}, + {".0", true, math.NewDec(0)}, + {"1.", true, math.NewDec(1)}, + {"foobar", true, math.Dec{}}, + {"0.foobar", true, math.Dec{}}, + {"0.foobar.", true, math.Dec{}}, + {"8888888888888888888888888888888888888888888888888888888888888888888844444440", false, math.NewDecFromBigInt(largerBigInt)}, + {"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535", false, math.NewDecFromBigIntWithPrec(largestBigInt, 18)}, + {"133499189745056880149688856635597007162669032647290798121690100488888732861291", true, math.Dec{}}, + } + + for tcIndex, tc := range tests { + res, err := math.NewDecFromStr(tc.decimalStr) + if tc.expErr { + s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + } else { + s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + s.Require().True(res.Equal(tc.exp), "equality was incorrect, res %v, exp %v, tc %v", res, tc.exp, tcIndex) + } + + // negative tc + res, err = math.NewDecFromStr("-" + tc.decimalStr) + if tc.expErr { + s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + } else { + s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) + exp := tc.exp.Mul(math.NewDec(-1)) + s.Require().True(res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex) + } + } +} + +func (s *decimalTestSuite) TestDecString() { + tests := []struct { + d math.Dec + want string + }{ + {math.NewDec(0), "0.000000000000000000"}, + {math.NewDec(1), "1.000000000000000000"}, + {math.NewDec(10), "10.000000000000000000"}, + {math.NewDec(12340), "12340.000000000000000000"}, + {math.NewDecWithPrec(12340, 4), "1.234000000000000000"}, + {math.NewDecWithPrec(12340, 5), "0.123400000000000000"}, + {math.NewDecWithPrec(12340, 8), "0.000123400000000000"}, + {math.NewDecWithPrec(1009009009009009009, 17), "10.090090090090090090"}, + } + for tcIndex, tc := range tests { + s.Require().Equal(tc.want, tc.d.String(), "bad String(), index: %v", tcIndex) + } +} + +func (s *decimalTestSuite) TestDecFloat64() { + tests := []struct { + d math.Dec + want float64 + }{ + {math.NewDec(0), 0.000000000000000000}, + {math.NewDec(1), 1.000000000000000000}, + {math.NewDec(10), 10.000000000000000000}, + {math.NewDec(12340), 12340.000000000000000000}, + {math.NewDecWithPrec(12340, 4), 1.234000000000000000}, + {math.NewDecWithPrec(12340, 5), 0.123400000000000000}, + {math.NewDecWithPrec(12340, 8), 0.000123400000000000}, + {math.NewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, + } + for tcIndex, tc := range tests { + value, err := tc.d.Float64() + s.Require().Nil(err, "error getting Float64(), index: %v", tcIndex) + s.Require().Equal(tc.want, value, "bad Float64(), index: %v", tcIndex) + s.Require().Equal(tc.want, tc.d.MustFloat64(), "bad MustFloat64(), index: %v", tcIndex) + } +} + +func (s *decimalTestSuite) TestEqualities() { + tests := []struct { + d1, d2 math.Dec + gt, lt, eq bool + }{ + {math.NewDec(0), math.NewDec(0), false, false, true}, + {math.NewDecWithPrec(0, 2), math.NewDecWithPrec(0, 4), false, false, true}, + {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(100, 0), false, false, true}, + {math.NewDecWithPrec(-100, 0), math.NewDecWithPrec(-100, 0), false, false, true}, + {math.NewDecWithPrec(-1, 1), math.NewDecWithPrec(-1, 1), false, false, true}, + {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(3333, 3), false, false, true}, + + {math.NewDecWithPrec(0, 0), math.NewDecWithPrec(3333, 3), false, true, false}, + {math.NewDecWithPrec(0, 0), math.NewDecWithPrec(100, 0), false, true, false}, + {math.NewDecWithPrec(-1, 0), math.NewDecWithPrec(3333, 3), false, true, false}, + {math.NewDecWithPrec(-1, 0), math.NewDecWithPrec(100, 0), false, true, false}, + {math.NewDecWithPrec(1111, 3), math.NewDecWithPrec(100, 0), false, true, false}, + {math.NewDecWithPrec(1111, 3), math.NewDecWithPrec(3333, 3), false, true, false}, + {math.NewDecWithPrec(-3333, 3), math.NewDecWithPrec(-1111, 3), false, true, false}, + + {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(0, 0), true, false, false}, + {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(0, 0), true, false, false}, + {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(-1, 0), true, false, false}, + {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(-1, 0), true, false, false}, + {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(1111, 3), true, false, false}, + {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(1111, 3), true, false, false}, + {math.NewDecWithPrec(-1111, 3), math.NewDecWithPrec(-3333, 3), true, false, false}, + } + + for tcIndex, tc := range tests { + s.Require().Equal(tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestDecsEqual() { + tests := []struct { + d1s, d2s []math.Dec + eq bool + }{ + {[]math.Dec{math.NewDec(0)}, []math.Dec{math.NewDec(0)}, true}, + {[]math.Dec{math.NewDec(0)}, []math.Dec{math.NewDec(1)}, false}, + {[]math.Dec{math.NewDec(0)}, []math.Dec{}, false}, + {[]math.Dec{math.NewDec(0), math.NewDec(1)}, []math.Dec{math.NewDec(0), math.NewDec(1)}, true}, + {[]math.Dec{math.NewDec(1), math.NewDec(0)}, []math.Dec{math.NewDec(1), math.NewDec(0)}, true}, + {[]math.Dec{math.NewDec(1), math.NewDec(0)}, []math.Dec{math.NewDec(0), math.NewDec(1)}, false}, + {[]math.Dec{math.NewDec(1), math.NewDec(0)}, []math.Dec{math.NewDec(1)}, false}, + {[]math.Dec{math.NewDec(1), math.NewDec(2)}, []math.Dec{math.NewDec(2), math.NewDec(4)}, false}, + {[]math.Dec{math.NewDec(3), math.NewDec(18)}, []math.Dec{math.NewDec(1), math.NewDec(6)}, false}, + } + + for tcIndex, tc := range tests { + s.Require().Equal(tc.eq, math.DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.eq, math.DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestArithmetic() { + tests := []struct { + d1, d2 math.Dec + expMul, expMulTruncate math.Dec + expQuo, expQuoRoundUp, expQuoTruncate math.Dec + expAdd, expSub math.Dec + }{ + // d1 d2 MUL MulTruncate QUO QUORoundUp QUOTrunctate ADD SUB + {math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0)}, + {math.NewDec(1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(1), math.NewDec(1)}, + {math.NewDec(0), math.NewDec(1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(1), math.NewDec(-1)}, + {math.NewDec(0), math.NewDec(-1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(-1), math.NewDec(1)}, + {math.NewDec(-1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(-1), math.NewDec(-1)}, + + {math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(2), math.NewDec(0)}, + {math.NewDec(-1), math.NewDec(-1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(-2), math.NewDec(0)}, + {math.NewDec(1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(0), math.NewDec(2)}, + {math.NewDec(-1), math.NewDec(1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(0), math.NewDec(-2)}, + + { + math.NewDec(3), math.NewDec(7), math.NewDec(21), math.NewDec(21), + math.NewDecWithPrec(428571428571428571, 18), math.NewDecWithPrec(428571428571428572, 18), math.NewDecWithPrec(428571428571428571, 18), + math.NewDec(10), math.NewDec(-4), + }, + { + math.NewDec(2), math.NewDec(4), math.NewDec(8), math.NewDec(8), math.NewDecWithPrec(5, 1), math.NewDecWithPrec(5, 1), math.NewDecWithPrec(5, 1), + math.NewDec(6), math.NewDec(-2), + }, + + {math.NewDec(100), math.NewDec(100), math.NewDec(10000), math.NewDec(10000), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(200), math.NewDec(0)}, + + { + math.NewDecWithPrec(15, 1), math.NewDecWithPrec(15, 1), math.NewDecWithPrec(225, 2), math.NewDecWithPrec(225, 2), + math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(3), math.NewDec(0), + }, + { + math.NewDecWithPrec(3333, 4), math.NewDecWithPrec(333, 4), math.NewDecWithPrec(1109889, 8), math.NewDecWithPrec(1109889, 8), + math.MustNewDecFromStr("10.009009009009009009"), math.MustNewDecFromStr("10.009009009009009010"), math.MustNewDecFromStr("10.009009009009009009"), + math.NewDecWithPrec(3666, 4), math.NewDecWithPrec(3, 1), + }, + } + + for tcIndex, tc := range tests { + tc := tc + resAdd := tc.d1.Add(tc.d2) + resSub := tc.d1.Sub(tc.d2) + resMul := tc.d1.Mul(tc.d2) + resMulTruncate := tc.d1.MulTruncate(tc.d2) + s.Require().True(tc.expAdd.Equal(resAdd), "exp %v, res %v, tc %d", tc.expAdd, resAdd, tcIndex) + s.Require().True(tc.expSub.Equal(resSub), "exp %v, res %v, tc %d", tc.expSub, resSub, tcIndex) + s.Require().True(tc.expMul.Equal(resMul), "exp %v, res %v, tc %d", tc.expMul, resMul, tcIndex) + s.Require().True(tc.expMulTruncate.Equal(resMulTruncate), "exp %v, res %v, tc %d", tc.expMulTruncate, resMulTruncate, tcIndex) + + if tc.d2.IsZero() { // panic for divide by zero + s.Require().Panics(func() { tc.d1.Quo(tc.d2) }) + } else { + resQuo := tc.d1.Quo(tc.d2) + s.Require().True(tc.expQuo.Equal(resQuo), "exp %v, res %v, tc %d", tc.expQuo.String(), resQuo.String(), tcIndex) + + resQuoRoundUp := tc.d1.QuoRoundUp(tc.d2) + s.Require().True(tc.expQuoRoundUp.Equal(resQuoRoundUp), "exp %v, res %v, tc %d", + tc.expQuoRoundUp.String(), resQuoRoundUp.String(), tcIndex) + + resQuoTruncate := tc.d1.QuoTruncate(tc.d2) + s.Require().True(tc.expQuoTruncate.Equal(resQuoTruncate), "exp %v, res %v, tc %d", + tc.expQuoTruncate.String(), resQuoTruncate.String(), tcIndex) + } + } +} + +func (s *decimalTestSuite) TestBankerRoundChop() { + tests := []struct { + d1 math.Dec + exp int64 + }{ + {s.mustNewDecFromStr("0.25"), 0}, + {s.mustNewDecFromStr("0"), 0}, + {s.mustNewDecFromStr("1"), 1}, + {s.mustNewDecFromStr("0.75"), 1}, + {s.mustNewDecFromStr("0.5"), 0}, + {s.mustNewDecFromStr("7.5"), 8}, + {s.mustNewDecFromStr("1.5"), 2}, + {s.mustNewDecFromStr("2.5"), 2}, + {s.mustNewDecFromStr("0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even + {s.mustNewDecFromStr("1.545"), 2}, + } + + for tcIndex, tc := range tests { + resNeg := tc.d1.Neg().RoundInt64() + s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) + + resPos := tc.d1.RoundInt64() + s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestTruncate() { + tests := []struct { + d1 math.Dec + exp int64 + }{ + {s.mustNewDecFromStr("0"), 0}, + {s.mustNewDecFromStr("0.25"), 0}, + {s.mustNewDecFromStr("0.75"), 0}, + {s.mustNewDecFromStr("1"), 1}, + {s.mustNewDecFromStr("1.5"), 1}, + {s.mustNewDecFromStr("7.5"), 7}, + {s.mustNewDecFromStr("7.6"), 7}, + {s.mustNewDecFromStr("7.4"), 7}, + {s.mustNewDecFromStr("100.1"), 100}, + {s.mustNewDecFromStr("1000.1"), 1000}, + } + + for tcIndex, tc := range tests { + resNeg := tc.d1.Neg().TruncateInt64() + s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) + + resPos := tc.d1.TruncateInt64() + s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) + } +} + +func (s *decimalTestSuite) TestStringOverflow() { + // two random 64 bit primes + dec1, err := math.NewDecFromStr("51643150036226787134389711697696177267") + s.Require().NoError(err) + dec2, err := math.NewDecFromStr("-31798496660535729618459429845579852627") + s.Require().NoError(err) + dec3 := dec1.Add(dec2) + s.Require().Equal( + "19844653375691057515930281852116324640.000000000000000000", + dec3.String(), + ) +} + +func (s *decimalTestSuite) TestDecMulInt() { + tests := []struct { + sdkDec math.Dec + sdkInt math.Int + want math.Dec + }{ + {math.NewDec(10), math.NewInt(2), math.NewDec(20)}, + {math.NewDec(1000000), math.NewInt(100), math.NewDec(100000000)}, + {math.NewDecWithPrec(1, 1), math.NewInt(10), math.NewDec(1)}, + {math.NewDecWithPrec(1, 5), math.NewInt(20), math.NewDecWithPrec(2, 4)}, + } + for i, tc := range tests { + got := tc.sdkDec.MulInt(tc.sdkInt) + s.Require().Equal(tc.want, got, "Incorrect result on test case %d", i) + } +} + +func (s *decimalTestSuite) TestDecCeil() { + testCases := []struct { + input math.Dec + expected math.Dec + }{ + {math.NewDecWithPrec(1000000000000000, math.Precision), math.NewDec(1)}, // 0.001 => 1.0 + {math.NewDecWithPrec(-1000000000000000, math.Precision), math.ZeroDec()}, // -0.001 => 0.0 + {math.ZeroDec(), math.ZeroDec()}, // 0.0 => 0.0 + {math.NewDecWithPrec(900000000000000000, math.Precision), math.NewDec(1)}, // 0.9 => 1.0 + {math.NewDecWithPrec(4001000000000000000, math.Precision), math.NewDec(5)}, // 4.001 => 5.0 + {math.NewDecWithPrec(-4001000000000000000, math.Precision), math.NewDec(-4)}, // -4.001 => -4.0 + {math.NewDecWithPrec(4700000000000000000, math.Precision), math.NewDec(5)}, // 4.7 => 5.0 + {math.NewDecWithPrec(-4700000000000000000, math.Precision), math.NewDec(-4)}, // -4.7 => -4.0 + } + + for i, tc := range testCases { + res := tc.input.Ceil() + s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestPower() { + testCases := []struct { + input math.Dec + power uint64 + expected math.Dec + }{ + {math.NewDec(100), 0, math.OneDec()}, // 10 ^ (0) => 1.0 + {math.OneDec(), 10, math.OneDec()}, // 1.0 ^ (10) => 1.0 + {math.NewDecWithPrec(5, 1), 2, math.NewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 + {math.NewDecWithPrec(2, 1), 2, math.NewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 + {math.NewDecFromInt(math.NewInt(3)), 3, math.NewDecFromInt(math.NewInt(27))}, // 3 ^ 3 => 27 + {math.NewDecFromInt(math.NewInt(-3)), 4, math.NewDecFromInt(math.NewInt(81))}, // -3 ^ 4 = 81 + {math.NewDecWithPrec(1414213562373095049, 18), 2, math.NewDecFromInt(math.NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 + } + + for i, tc := range testCases { + res := tc.input.Power(tc.power) + s.Require().True(tc.expected.Sub(res).Abs().LTE(math.SmallestDec()), "unexpected result for test case %d, normal power, input: %v", i, tc.input) + + mutableInput := tc.input + mutableInput.PowerMut(tc.power) + s.Require().True(tc.expected.Sub(mutableInput).Abs().LTE(math.SmallestDec()), + "unexpected result for test case %d, input %v", i, tc.input) + s.Require().True(res.Equal(tc.input), "unexpected result for test case %d, mutable power, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestApproxRoot() { + testCases := []struct { + input math.Dec + root uint64 + expected math.Dec + }{ + {math.OneDec(), 10, math.OneDec()}, // 1.0 ^ (0.1) => 1.0 + {math.NewDecWithPrec(25, 2), 2, math.NewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 + {math.NewDecWithPrec(4, 2), 2, math.NewDecWithPrec(2, 1)}, // 0.04 ^ (0.5) => 0.2 + {math.NewDecFromInt(math.NewInt(27)), 3, math.NewDecFromInt(math.NewInt(3))}, // 27 ^ (1/3) => 3 + {math.NewDecFromInt(math.NewInt(-81)), 4, math.NewDecFromInt(math.NewInt(-3))}, // -81 ^ (0.25) => -3 + {math.NewDecFromInt(math.NewInt(2)), 2, math.NewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 + {math.NewDecWithPrec(1005, 3), 31536000, math.MustNewDecFromStr("1.000000000158153904")}, // 1.005 ^ (1/31536000) ≈ 1.00000000016 + {math.SmallestDec(), 2, math.NewDecWithPrec(1, 9)}, // 1e-18 ^ (0.5) => 1e-9 + {math.SmallestDec(), 3, math.MustNewDecFromStr("0.000000999999999997")}, // 1e-18 ^ (1/3) => 1e-6 + {math.NewDecWithPrec(1, 8), 3, math.MustNewDecFromStr("0.002154434690031900")}, // 1e-8 ^ (1/3) ≈ 0.00215443469 + {math.MustNewDecFromStr("9000002314687921634000000000000000000021394871242000000000000000"), 2, math.MustNewDecFromStr("94868342004527103646332858502867.899477053226766107")}, + } + + // In the case of 1e-8 ^ (1/3), the result repeats every 5 iterations starting from iteration 24 + // (i.e. 24, 29, 34, ... give the same result) and never converges enough. The maximum number of + // iterations (300) causes the result at iteration 300 to be returned, regardless of convergence. + + for i, tc := range testCases { + res, err := tc.input.ApproxRoot(tc.root) + s.Require().NoError(err) + s.Require().True(tc.expected.Sub(res).Abs().LTE(math.SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestApproxSqrt() { + testCases := []struct { + input math.Dec + expected math.Dec + }{ + {math.OneDec(), math.OneDec()}, // 1.0 => 1.0 + {math.NewDecWithPrec(25, 2), math.NewDecWithPrec(5, 1)}, // 0.25 => 0.5 + {math.NewDecWithPrec(4, 2), math.NewDecWithPrec(2, 1)}, // 0.09 => 0.3 + {math.NewDecFromInt(math.NewInt(9)), math.NewDecFromInt(math.NewInt(3))}, // 9 => 3 + {math.NewDecFromInt(math.NewInt(-9)), math.NewDecFromInt(math.NewInt(-3))}, // -9 => -3 + {math.NewDecFromInt(math.NewInt(2)), math.NewDecWithPrec(1414213562373095049, 18)}, // 2 => 1.414213562373095049 + } + + for i, tc := range testCases { + res, err := tc.input.ApproxSqrt() + s.Require().NoError(err) + s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func (s *decimalTestSuite) TestDecSortableBytes() { + tests := []struct { + d math.Dec + want []byte + }{ + {math.NewDec(0), []byte("000000000000000000.000000000000000000")}, + {math.NewDec(1), []byte("000000000000000001.000000000000000000")}, + {math.NewDec(10), []byte("000000000000000010.000000000000000000")}, + {math.NewDec(12340), []byte("000000000000012340.000000000000000000")}, + {math.NewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, + {math.NewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, + {math.NewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, + {math.NewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, + {math.NewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, + {math.NewDec(1000000000000000000), []byte("max")}, + {math.NewDec(-1000000000000000000), []byte("--")}, + } + for tcIndex, tc := range tests { + s.Require().Equal(tc.want, math.SortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) + } + + s.Require().Panics(func() { math.SortableDecBytes(math.NewDec(1000000000000000001)) }) + s.Require().Panics(func() { math.SortableDecBytes(math.NewDec(-1000000000000000001)) }) +} + +func (s *decimalTestSuite) TestDecEncoding() { + largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) + s.Require().True(ok) + + smallestBigInt, ok := new(big.Int).SetString("-33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) + s.Require().True(ok) + + const maxDecBitLen = 315 + maxInt, ok := new(big.Int).SetString(strings.Repeat("1", maxDecBitLen), 2) + s.Require().True(ok) + + testCases := []struct { + input math.Dec + rawBz string + jsonStr string + yamlStr string + }{ + { + math.NewDec(0), "30", + "\"0.000000000000000000\"", + "\"0.000000000000000000\"\n", + }, + { + math.NewDecWithPrec(4, 2), + "3430303030303030303030303030303030", + "\"0.040000000000000000\"", + "\"0.040000000000000000\"\n", + }, + { + math.NewDecWithPrec(-4, 2), + "2D3430303030303030303030303030303030", + "\"-0.040000000000000000\"", + "\"-0.040000000000000000\"\n", + }, + { + math.NewDecWithPrec(1414213562373095049, 18), + "31343134323133353632333733303935303439", + "\"1.414213562373095049\"", + "\"1.414213562373095049\"\n", + }, + { + math.NewDecWithPrec(-1414213562373095049, 18), + "2D31343134323133353632333733303935303439", + "\"-1.414213562373095049\"", + "\"-1.414213562373095049\"\n", + }, + { + math.NewDecFromBigIntWithPrec(largestBigInt, 18), + "3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", + "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", + "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", + }, + { + math.NewDecFromBigIntWithPrec(smallestBigInt, 18), + "2D3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", + "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", + "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", + }, + { + math.NewDecFromBigIntWithPrec(maxInt, 18), + "3636373439353934383732353238343430303734383434343238333137373938353033353831333334353136333233363435333939303630383435303530323434343434333636343330363435303137313838323137353635323136373637", + "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"", + "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"\n", + }, + } + + for _, tc := range testCases { + bz, err := tc.input.Marshal() + s.Require().NoError(err) + s.Require().Equal(tc.rawBz, fmt.Sprintf("%X", bz)) + + var other math.Dec + s.Require().NoError((&other).Unmarshal(bz)) + s.Require().True(tc.input.Equal(other)) + + bz, err = json.Marshal(tc.input) + s.Require().NoError(err) + s.Require().Equal(tc.jsonStr, string(bz)) + s.Require().NoError(json.Unmarshal(bz, &other)) + s.Require().True(tc.input.Equal(other)) + + bz, err = yaml.Marshal(tc.input) + s.Require().NoError(err) + s.Require().Equal(tc.yamlStr, string(bz)) + } +} + +// Showcase that different orders of operations causes different results. +func (s *decimalTestSuite) TestOperationOrders() { + n1 := math.NewDec(10) + n2 := math.NewDec(1000000010) + s.Require().Equal(n1.Mul(n2).Quo(n2), math.NewDec(10)) + s.Require().NotEqual(n1.Mul(n2).Quo(n2), n1.Quo(n2).Mul(n2)) +} + +func BenchmarkMarshalTo(b *testing.B) { + b.ReportAllocs() + bis := []struct { + in math.Dec + want []byte + }{ + { + math.NewDec(1e8), []byte{ + 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + }, + }, + {math.NewDec(0), []byte{0x30}}, + } + data := make([]byte, 100) + + b.ReportAllocs() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, bi := range bis { + if n, err := bi.in.MarshalTo(data); err != nil { + b.Fatal(err) + } else { + if !bytes.Equal(data[:n], bi.want) { + b.Fatalf("Mismatch\nGot: % x\nWant: % x\n", data[:n], bi.want) + } + } + } + } +} diff --git a/math/go.mod b/math/go.mod index 0fc26ea1a96b..8d808843efbc 100644 --- a/math/go.mod +++ b/math/go.mod @@ -2,10 +2,14 @@ module cosmossdk.io/math go 1.18 -require github.com/stretchr/testify v1.8.0 +require ( + github.com/stretchr/testify v1.8.0 + sigs.k8s.io/yaml v1.3.0 +) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/math/go.sum b/math/go.sum index 51648299d59e..341b49b6f410 100644 --- a/math/go.sum +++ b/math/go.sum @@ -10,6 +10,10 @@ github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PK github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/types/decimal.go b/types/decimal.go index ca9dc3ca5730..f7be3ad4a2ca 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -1,900 +1,5 @@ package types -import ( - "encoding/json" - "errors" - "fmt" - "math/big" - "strconv" - "strings" - "testing" -) - -var _ CustomProtobufType = (*Dec)(nil) - -// NOTE: never use new(Dec) or else we will panic unmarshalling into the -// nil embedded big.Int -type Dec struct { - i *big.Int -} - -const ( - // number of decimal places - Precision = 18 - - // bits required to represent the above precision - // Ceiling[Log2[10^Precision - 1]] - DecimalPrecisionBits = 60 - - // decimalTruncateBits is the minimum number of bits removed - // by a truncate operation. It is equal to - // Floor[Log2[10^Precision - 1]]. - decimalTruncateBits = DecimalPrecisionBits - 1 - - maxDecBitLen = MaxBitLen + decimalTruncateBits - - // max number of iterations in ApproxRoot function - maxApproxRootIterations = 300 -) - -var ( - precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) - fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) - precisionMultipliers []*big.Int - zeroInt = big.NewInt(0) - oneInt = big.NewInt(1) - tenInt = big.NewInt(10) -) - -// Decimal errors -var ( - ErrEmptyDecimalStr = errors.New("decimal string cannot be empty") - ErrInvalidDecimalLength = errors.New("invalid decimal length") - ErrInvalidDecimalStr = errors.New("invalid decimal string") -) - -// Set precision multipliers -func init() { - precisionMultipliers = make([]*big.Int, Precision+1) - for i := 0; i <= Precision; i++ { - precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) - } -} - -func precisionInt() *big.Int { - return new(big.Int).Set(precisionReuse) -} - -func ZeroDec() Dec { return Dec{new(big.Int).Set(zeroInt)} } -func OneDec() Dec { return Dec{precisionInt()} } -func SmallestDec() Dec { return Dec{new(big.Int).Set(oneInt)} } - -// calculate the precision multiplier -func calcPrecisionMultiplier(prec int64) *big.Int { - if prec > Precision { - panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) - } - zerosToAdd := Precision - prec - multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) - return multiplier -} - -// get the precision multiplier, do not mutate result -func precisionMultiplier(prec int64) *big.Int { - if prec > Precision { - panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) - } - return precisionMultipliers[prec] -} - -// create a new Dec from integer assuming whole number -func NewDec(i int64) Dec { - return NewDecWithPrec(i, 0) -} - -// create a new Dec from integer with decimal place at prec -// CONTRACT: prec <= Precision -func NewDecWithPrec(i, prec int64) Dec { - return Dec{ - new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), - } -} - -// create a new Dec from big integer assuming whole numbers -// CONTRACT: prec <= Precision -func NewDecFromBigInt(i *big.Int) Dec { - return NewDecFromBigIntWithPrec(i, 0) -} - -// create a new Dec from big integer assuming whole numbers -// CONTRACT: prec <= Precision -func NewDecFromBigIntWithPrec(i *big.Int, prec int64) Dec { - return Dec{ - new(big.Int).Mul(i, precisionMultiplier(prec)), - } -} - -// create a new Dec from big integer assuming whole numbers -// CONTRACT: prec <= Precision -func NewDecFromInt(i Int) Dec { - return NewDecFromIntWithPrec(i, 0) -} - -// create a new Dec from big integer with decimal place at prec -// CONTRACT: prec <= Precision -func NewDecFromIntWithPrec(i Int, prec int64) Dec { - return Dec{ - new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), - } -} - -// create a decimal from an input decimal string. -// valid must come in the form: -// (-) whole integers (.) decimal integers -// examples of acceptable input include: -// -123.456 -// 456.7890 -// 345 -// -456789 -// -// NOTE - An error will return if more decimal places -// are provided in the string than the constant Precision. -// -// CONTRACT - This function does not mutate the input str. -func NewDecFromStr(str string) (Dec, error) { - if len(str) == 0 { - return Dec{}, fmt.Errorf("%s: %w", str, ErrEmptyDecimalStr) - } - - // first extract any negative symbol - neg := false - if str[0] == '-' { - neg = true - str = str[1:] - } - - if len(str) == 0 { - return Dec{}, fmt.Errorf("%s: %w", str, ErrEmptyDecimalStr) - } - - strs := strings.Split(str, ".") - lenDecs := 0 - combinedStr := strs[0] - - if len(strs) == 2 { // has a decimal place - lenDecs = len(strs[1]) - if lenDecs == 0 || len(combinedStr) == 0 { - return Dec{}, ErrInvalidDecimalLength - } - combinedStr += strs[1] - } else if len(strs) > 2 { - return Dec{}, ErrInvalidDecimalStr - } - - if lenDecs > Precision { - return Dec{}, fmt.Errorf("value '%s' exceeds max precision by %d decimal places: max precision %d", str, Precision-lenDecs, Precision) - } - - // add some extra zero's to correct to the Precision factor - zerosToAdd := Precision - lenDecs - zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "") - combinedStr += zeros - - combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 - if !ok { - return Dec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr) - } - if combined.BitLen() > maxDecBitLen { - return Dec{}, fmt.Errorf("decimal '%s' out of range; bitLen: got %d, max %d", str, combined.BitLen(), maxDecBitLen) - } - if neg { - combined = new(big.Int).Neg(combined) - } - - return Dec{combined}, nil -} - -// Decimal from string, panic on error -func MustNewDecFromStr(s string) Dec { - dec, err := NewDecFromStr(s) - if err != nil { - panic(err) - } - return dec -} - -func (d Dec) IsNil() bool { return d.i == nil } // is decimal nil -func (d Dec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero -func (d Dec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative -func (d Dec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive -func (d Dec) Equal(d2 Dec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals -func (d Dec) GT(d2 Dec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than -func (d Dec) GTE(d2 Dec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal -func (d Dec) LT(d2 Dec) bool { return (d.i).Cmp(d2.i) < 0 } // less than -func (d Dec) LTE(d2 Dec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.i)} } // reverse the decimal sign -func (d Dec) NegMut() Dec { d.i.Neg(d.i); return d } // reverse the decimal sign, mutable -func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.i)} } // absolute value -func (d Dec) Set(d2 Dec) Dec { d.i.Set(d2.i); return d } // set to existing dec value -func (d Dec) Clone() Dec { return Dec{new(big.Int).Set(d.i)} } // clone new dec - -// BigInt returns a copy of the underlying big.Int. -func (d Dec) BigInt() *big.Int { - if d.IsNil() { - return nil - } - - cp := new(big.Int) - return cp.Set(d.i) -} - -func (d Dec) ImmutOp(op func(Dec, Dec) Dec, d2 Dec) Dec { - return op(d.Clone(), d2) -} - -func (d Dec) ImmutOpInt(op func(Dec, Int) Dec, d2 Int) Dec { - return op(d.Clone(), d2) -} - -func (d Dec) ImmutOpInt64(op func(Dec, int64) Dec, d2 int64) Dec { - // TODO: use already allocated operand bigint to avoid - // newint each time, add mutex for race condition - // Issue: https://github.com/cosmos/cosmos-sdk/issues/11166 - return op(d.Clone(), d2) -} - -func (d Dec) SetInt64(i int64) Dec { - d.i.SetInt64(i) - d.i.Mul(d.i, precisionReuse) - return d -} - -// addition -func (d Dec) Add(d2 Dec) Dec { - return d.ImmutOp(Dec.AddMut, d2) -} - -// mutable addition -func (d Dec) AddMut(d2 Dec) Dec { - d.i.Add(d.i, d2.i) - - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// subtraction -func (d Dec) Sub(d2 Dec) Dec { - return d.ImmutOp(Dec.SubMut, d2) -} - -// mutable subtraction -func (d Dec) SubMut(d2 Dec) Dec { - d.i.Sub(d.i, d2.i) - - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// multiplication -func (d Dec) Mul(d2 Dec) Dec { - return d.ImmutOp(Dec.MulMut, d2) -} - -// mutable multiplication -func (d Dec) MulMut(d2 Dec) Dec { - d.i.Mul(d.i, d2.i) - chopped := chopPrecisionAndRound(d.i) - - if chopped.BitLen() > maxDecBitLen { - panic("Int overflow") - } - *d.i = *chopped - return d -} - -// multiplication truncate -func (d Dec) MulTruncate(d2 Dec) Dec { - return d.ImmutOp(Dec.MulTruncateMut, d2) -} - -// mutable multiplication truncage -func (d Dec) MulTruncateMut(d2 Dec) Dec { - d.i.Mul(d.i, d2.i) - chopPrecisionAndTruncate(d.i) - - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// multiplication -func (d Dec) MulInt(i Int) Dec { - return d.ImmutOpInt(Dec.MulIntMut, i) -} - -func (d Dec) MulIntMut(i Int) Dec { - d.i.Mul(d.i, i.BigInt()) - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// MulInt64 - multiplication with int64 -func (d Dec) MulInt64(i int64) Dec { - return d.ImmutOpInt64(Dec.MulInt64Mut, i) -} - -func (d Dec) MulInt64Mut(i int64) Dec { - d.i.Mul(d.i, big.NewInt(i)) - - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// quotient -func (d Dec) Quo(d2 Dec) Dec { - return d.ImmutOp(Dec.QuoMut, d2) -} - -// mutable quotient -func (d Dec) QuoMut(d2 Dec) Dec { - // multiply precision twice - d.i.Mul(d.i, precisionReuse) - d.i.Mul(d.i, precisionReuse) - d.i.Quo(d.i, d2.i) - - chopPrecisionAndRound(d.i) - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// quotient truncate -func (d Dec) QuoTruncate(d2 Dec) Dec { - return d.ImmutOp(Dec.QuoTruncateMut, d2) -} - -// mutable quotient truncate -func (d Dec) QuoTruncateMut(d2 Dec) Dec { - // multiply precision twice - d.i.Mul(d.i, precisionReuse) - d.i.Mul(d.i, precisionReuse) - d.i.Quo(d.i, d2.i) - - chopPrecisionAndTruncate(d.i) - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// quotient, round up -func (d Dec) QuoRoundUp(d2 Dec) Dec { - return d.ImmutOp(Dec.QuoRoundupMut, d2) -} - -// mutable quotient, round up -func (d Dec) QuoRoundupMut(d2 Dec) Dec { - // multiply precision twice - d.i.Mul(d.i, precisionReuse) - d.i.Mul(d.i, precisionReuse) - d.i.Quo(d.i, d2.i) - - chopPrecisionAndRoundUp(d.i) - if d.i.BitLen() > maxDecBitLen { - panic("Int overflow") - } - return d -} - -// quotient -func (d Dec) QuoInt(i Int) Dec { - return d.ImmutOpInt(Dec.QuoIntMut, i) -} - -func (d Dec) QuoIntMut(i Int) Dec { - d.i.Quo(d.i, i.BigInt()) - return d -} - -// QuoInt64 - quotient with int64 -func (d Dec) QuoInt64(i int64) Dec { - return d.ImmutOpInt64(Dec.QuoInt64Mut, i) -} - -func (d Dec) QuoInt64Mut(i int64) Dec { - d.i.Quo(d.i, big.NewInt(i)) - return d -} - -// ApproxRoot returns an approximate estimation of a Dec's positive real nth root -// using Newton's method (where n is positive). The algorithm starts with some guess and -// computes the sequence of improved guesses until an answer converges to an -// approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. -// A maximum number of 100 iterations is used a backup boundary condition for -// cases where the answer never converges enough to satisfy the main condition. -func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { - defer func() { - if r := recover(); r != nil { - var ok bool - err, ok = r.(error) - if !ok { - err = errors.New("out of bounds") - } - } - }() - - if d.IsNegative() { - absRoot, err := d.Neg().ApproxRoot(root) - return absRoot.NegMut(), err - } - - if root == 1 || d.IsZero() || d.Equal(OneDec()) { - return d, nil - } - - if root == 0 { - return OneDec(), nil - } - - guess, delta := OneDec(), OneDec() - - for iter := 0; delta.Abs().GT(SmallestDec()) && iter < maxApproxRootIterations; iter++ { - prev := guess.Power(root - 1) - if prev.IsZero() { - prev = SmallestDec() - } - delta.Set(d).QuoMut(prev) - delta.SubMut(guess) - delta.QuoInt64Mut(int64(root)) - - guess.AddMut(delta) - } - - return guess, nil -} - -// Power returns a the result of raising to a positive integer power -func (d Dec) Power(power uint64) Dec { - res := Dec{new(big.Int).Set(d.i)} - return res.PowerMut(power) -} - -func (d Dec) PowerMut(power uint64) Dec { - if power == 0 { - d.SetInt64(1) - return d - } - tmp := OneDec() - - for i := power; i > 1; { - if i%2 != 0 { - tmp.MulMut(d) - } - i /= 2 - d.MulMut(d) - } - - return d.MulMut(tmp) -} - -// ApproxSqrt is a wrapper around ApproxRoot for the common special case -// of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. -func (d Dec) ApproxSqrt() (Dec, error) { - return d.ApproxRoot(2) -} - -// is integer, e.g. decimals are zero -func (d Dec) IsInteger() bool { - return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 -} - -// format decimal state -func (d Dec) Format(s fmt.State, verb rune) { - _, err := s.Write([]byte(d.String())) - if err != nil { - panic(err) - } -} - -func (d Dec) String() string { - if d.i == nil { - return d.i.String() - } - - isNeg := d.IsNegative() - - if isNeg { - d = d.Neg() - } - - bzInt, err := d.i.MarshalText() - if err != nil { - return "" - } - inputSize := len(bzInt) - - var bzStr []byte - - // TODO: Remove trailing zeros - // case 1, purely decimal - if inputSize <= Precision { - bzStr = make([]byte, Precision+2) - - // 0. prefix - bzStr[0] = byte('0') - bzStr[1] = byte('.') - - // set relevant digits to 0 - for i := 0; i < Precision-inputSize; i++ { - bzStr[i+2] = byte('0') - } - - // set final digits - copy(bzStr[2+(Precision-inputSize):], bzInt) - } else { - // inputSize + 1 to account for the decimal point that is being added - bzStr = make([]byte, inputSize+1) - decPointPlace := inputSize - Precision - - copy(bzStr, bzInt[:decPointPlace]) // pre-decimal digits - bzStr[decPointPlace] = byte('.') // decimal point - copy(bzStr[decPointPlace+1:], bzInt[decPointPlace:]) // post-decimal digits - } - - if isNeg { - return "-" + string(bzStr) - } - - return string(bzStr) -} - -// Float64 returns the float64 representation of a Dec. -// Will return the error if the conversion failed. -func (d Dec) Float64() (float64, error) { - return strconv.ParseFloat(d.String(), 64) -} - -// MustFloat64 returns the float64 representation of a Dec. -// Would panic if the conversion failed. -func (d Dec) MustFloat64() float64 { - if value, err := strconv.ParseFloat(d.String(), 64); err != nil { - panic(err) - } else { - return value - } -} - -// ____ -// __| |__ "chop 'em -// ` \ round!" -// ___|| ~ _ -bankers -// | | __ -// | | | __|__|__ -// |_____: / | $$$ | -// |________| - -// Remove a Precision amount of rightmost digits and perform bankers rounding -// on the remainder (gaussian rounding) on the digits which have been removed. -// -// Mutates the input. Use the non-mutative version if that is undesired -func chopPrecisionAndRound(d *big.Int) *big.Int { - // remove the negative and add it back when returning - if d.Sign() == -1 { - // make d positive, compute chopped value, and then un-mutate d - d = d.Neg(d) - d = chopPrecisionAndRound(d) - d = d.Neg(d) - return d - } - - // get the truncated quotient and remainder - quo, rem := d, big.NewInt(0) - quo, rem = quo.QuoRem(d, precisionReuse, rem) - - if rem.Sign() == 0 { // remainder is zero - return quo - } - - switch rem.Cmp(fivePrecision) { - case -1: - return quo - case 1: - return quo.Add(quo, oneInt) - default: // bankers rounding must take place - // always round to an even number - if quo.Bit(0) == 0 { - return quo - } - return quo.Add(quo, oneInt) - } -} - -func chopPrecisionAndRoundUp(d *big.Int) *big.Int { - // remove the negative and add it back when returning - if d.Sign() == -1 { - // make d positive, compute chopped value, and then un-mutate d - d = d.Neg(d) - // truncate since d is negative... - chopPrecisionAndTruncate(d) - d = d.Neg(d) - return d - } - - // get the truncated quotient and remainder - quo, rem := d, big.NewInt(0) - quo, rem = quo.QuoRem(d, precisionReuse, rem) - - if rem.Sign() == 0 { // remainder is zero - return quo - } - - return quo.Add(quo, oneInt) -} - -func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { - tmp := new(big.Int).Set(d) - return chopPrecisionAndRound(tmp) -} - -// RoundInt64 rounds the decimal using bankers rounding -func (d Dec) RoundInt64() int64 { - chopped := chopPrecisionAndRoundNonMutative(d.i) - if !chopped.IsInt64() { - panic("Int64() out of bound") - } - return chopped.Int64() -} - -// RoundInt round the decimal using bankers rounding -func (d Dec) RoundInt() Int { - return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.i)) -} - -// chopPrecisionAndTruncate is similar to chopPrecisionAndRound, -// but always rounds down. It does not mutate the input. -func chopPrecisionAndTruncate(d *big.Int) { - d.Quo(d, precisionReuse) -} - -func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { - tmp := new(big.Int).Set(d) - chopPrecisionAndTruncate(tmp) - return tmp -} - -// TruncateInt64 truncates the decimals from the number and returns an int64 -func (d Dec) TruncateInt64() int64 { - chopped := chopPrecisionAndTruncateNonMutative(d.i) - if !chopped.IsInt64() { - panic("Int64() out of bound") - } - return chopped.Int64() -} - -// TruncateInt truncates the decimals from the number and returns an Int -func (d Dec) TruncateInt() Int { - return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) -} - -// TruncateDec truncates the decimals from the number and returns a Dec -func (d Dec) TruncateDec() Dec { - return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) -} - -// Ceil returns the smallest interger value (as a decimal) that is greater than -// or equal to the given decimal. -func (d Dec) Ceil() Dec { - tmp := new(big.Int).Set(d.i) - - quo, rem := tmp, big.NewInt(0) - quo, rem = quo.QuoRem(tmp, precisionReuse, rem) - - // no need to round with a zero remainder regardless of sign - if rem.Cmp(zeroInt) == 0 { - return NewDecFromBigInt(quo) - } - - if rem.Sign() == -1 { - return NewDecFromBigInt(quo) - } - - return NewDecFromBigInt(quo.Add(quo, oneInt)) -} - -// MaxSortableDec is the largest Dec that can be passed into SortableDecBytes() -// Its negative form is the least Dec that can be passed in. -var MaxSortableDec Dec - -func init() { - MaxSortableDec = OneDec().Quo(SmallestDec()) -} - -// 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.Abs().LTE(MaxSortableDec) -} - -// 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") - } - // Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just - // makes its bytes be "max" which comes after all numbers in ASCIIbetical order - if dec.Equal(MaxSortableDec) { - return []byte("max") - } - // For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers. - if dec.Equal(MaxSortableDec.Neg()) { - return []byte("--") - } - // We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers - if dec.IsNegative() { - return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.Abs().String()))...) - } - return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.String())) -} - -// reuse nil values -var nilJSON []byte - -func init() { - empty := new(big.Int) - bz, _ := empty.MarshalText() - nilJSON, _ = json.Marshal(string(bz)) -} - -// MarshalJSON marshals the decimal -func (d Dec) MarshalJSON() ([]byte, error) { - if d.i == nil { - return nilJSON, nil - } - return json.Marshal(d.String()) -} - -// UnmarshalJSON defines custom decoding scheme -func (d *Dec) UnmarshalJSON(bz []byte) error { - if d.i == nil { - d.i = new(big.Int) - } - - var text string - err := json.Unmarshal(bz, &text) - if err != nil { - return err - } - - // TODO: Reuse dec allocation - newDec, err := NewDecFromStr(text) - if err != nil { - return err - } - - d.i = newDec.i - return nil -} - -// MarshalYAML returns the YAML representation. -func (d Dec) MarshalYAML() (interface{}, error) { - return d.String(), nil -} - -// Marshal implements the gogo proto custom type interface. -func (d Dec) Marshal() ([]byte, error) { - if d.i == nil { - d.i = new(big.Int) - } - return d.i.MarshalText() -} - -// MarshalTo implements the gogo proto custom type interface. -func (d *Dec) MarshalTo(data []byte) (n int, err error) { - if d.i == nil { - d.i = new(big.Int) - } - - if d.i.Cmp(zeroInt) == 0 { - copy(data, []byte{0x30}) - return 1, nil - } - - bz, err := d.Marshal() - if err != nil { - return 0, err - } - - copy(data, bz) - return len(bz), nil -} - -// Unmarshal implements the gogo proto custom type interface. -func (d *Dec) Unmarshal(data []byte) error { - if len(data) == 0 { - d = nil - return nil - } - - if d.i == nil { - d.i = new(big.Int) - } - - if err := d.i.UnmarshalText(data); err != nil { - return err - } - - if d.i.BitLen() > maxDecBitLen { - return fmt.Errorf("decimal out of range; got: %d, max: %d", d.i.BitLen(), maxDecBitLen) - } - - return nil -} - -// Size implements the gogo proto custom type interface. -func (d *Dec) Size() int { - bz, _ := d.Marshal() - return len(bz) -} - -// Override Amino binary serialization by proxying to protobuf. -func (d Dec) MarshalAmino() ([]byte, error) { return d.Marshal() } -func (d *Dec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } - func (dp DecProto) String() string { return dp.Dec.String() } - -// helpers - -// test if two decimal arrays are equal -func DecsEqual(d1s, d2s []Dec) bool { - if len(d1s) != len(d2s) { - return false - } - - for i, d1 := range d1s { - if !d1.Equal(d2s[i]) { - return false - } - } - return true -} - -// minimum decimal between two -func MinDec(d1, d2 Dec) Dec { - if d1.LT(d2) { - return d1 - } - return d2 -} - -// maximum decimal between two -func MaxDec(d1, d2 Dec) Dec { - if d1.LT(d2) { - return d2 - } - return d1 -} - -// intended to be used with require/assert: require.True(DecEq(...)) -func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, string, string) { - return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String() -} - -func DecApproxEq(t *testing.T, d1 Dec, d2 Dec, tol Dec) (*testing.T, bool, string, string, string) { - diff := d1.Sub(d2).Abs() - return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String() -} diff --git a/types/decimal_test.go b/types/decimal_test.go deleted file mode 100644 index 9416b94938aa..000000000000 --- a/types/decimal_test.go +++ /dev/null @@ -1,621 +0,0 @@ -package types_test - -import ( - "bytes" - "encoding/json" - "fmt" - "math/big" - "strings" - "testing" - - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - "sigs.k8s.io/yaml" - - sdk "github.com/cosmos/cosmos-sdk/types" -) - -type decimalTestSuite struct { - suite.Suite -} - -func TestDecimalTestSuite(t *testing.T) { - suite.Run(t, new(decimalTestSuite)) -} - -func TestDecApproxEq(t *testing.T) { - // d1 = 0.55, d2 = 0.6, tol = 0.1 - d1 := sdk.NewDecWithPrec(55, 2) - d2 := sdk.NewDecWithPrec(6, 1) - tol := sdk.NewDecWithPrec(1, 1) - - require.True(sdk.DecApproxEq(t, d1, d2, tol)) - - // d1 = 0.55, d2 = 0.6, tol = 1E-5 - d1 = sdk.NewDecWithPrec(55, 2) - d2 = sdk.NewDecWithPrec(6, 1) - tol = sdk.NewDecWithPrec(1, 5) - - require.False(sdk.DecApproxEq(t, d1, d2, tol)) - - // d1 = 0.6, d2 = 0.61, tol = 0.01 - d1 = sdk.NewDecWithPrec(6, 1) - d2 = sdk.NewDecWithPrec(61, 2) - tol = sdk.NewDecWithPrec(1, 2) - - require.True(sdk.DecApproxEq(t, d1, d2, tol)) -} - -// create a decimal from a decimal string (ex. "1234.5678") -func (s *decimalTestSuite) mustNewDecFromStr(str string) (d sdk.Dec) { - d, err := sdk.NewDecFromStr(str) - s.Require().NoError(err) - - return d -} - -func (s *decimalTestSuite) TestNewDecFromStr() { - largeBigInt, ok := new(big.Int).SetString("3144605511029693144278234343371835", 10) - s.Require().True(ok) - - largerBigInt, ok := new(big.Int).SetString("8888888888888888888888888888888888888888888888888888888888888888888844444440", 10) - s.Require().True(ok) - - largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) - s.Require().True(ok) - - tests := []struct { - decimalStr string - expErr bool - exp sdk.Dec - }{ - {"", true, sdk.Dec{}}, - {"0.-75", true, sdk.Dec{}}, - {"0", false, sdk.NewDec(0)}, - {"1", false, sdk.NewDec(1)}, - {"1.1", false, sdk.NewDecWithPrec(11, 1)}, - {"0.75", false, sdk.NewDecWithPrec(75, 2)}, - {"0.8", false, sdk.NewDecWithPrec(8, 1)}, - {"0.11111", false, sdk.NewDecWithPrec(11111, 5)}, - {"314460551102969.3144278234343371835", true, sdk.NewDec(3141203149163817869)}, - { - "314460551102969314427823434337.1835718092488231350", - true, sdk.NewDecFromBigIntWithPrec(largeBigInt, 4), - }, - { - "314460551102969314427823434337.1835", - false, sdk.NewDecFromBigIntWithPrec(largeBigInt, 4), - }, - {".", true, sdk.Dec{}}, - {".0", true, sdk.NewDec(0)}, - {"1.", true, sdk.NewDec(1)}, - {"foobar", true, sdk.Dec{}}, - {"0.foobar", true, sdk.Dec{}}, - {"0.foobar.", true, sdk.Dec{}}, - {"8888888888888888888888888888888888888888888888888888888888888888888844444440", false, sdk.NewDecFromBigInt(largerBigInt)}, - {"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535", false, sdk.NewDecFromBigIntWithPrec(largestBigInt, 18)}, - {"133499189745056880149688856635597007162669032647290798121690100488888732861291", true, sdk.Dec{}}, - } - - for tcIndex, tc := range tests { - res, err := sdk.NewDecFromStr(tc.decimalStr) - if tc.expErr { - s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - } else { - s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - s.Require().True(res.Equal(tc.exp), "equality was incorrect, res %v, exp %v, tc %v", res, tc.exp, tcIndex) - } - - // negative tc - res, err = sdk.NewDecFromStr("-" + tc.decimalStr) - if tc.expErr { - s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - } else { - s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - exp := tc.exp.Mul(sdk.NewDec(-1)) - s.Require().True(res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex) - } - } -} - -func (s *decimalTestSuite) TestDecString() { - tests := []struct { - d sdk.Dec - want string - }{ - {sdk.NewDec(0), "0.000000000000000000"}, - {sdk.NewDec(1), "1.000000000000000000"}, - {sdk.NewDec(10), "10.000000000000000000"}, - {sdk.NewDec(12340), "12340.000000000000000000"}, - {sdk.NewDecWithPrec(12340, 4), "1.234000000000000000"}, - {sdk.NewDecWithPrec(12340, 5), "0.123400000000000000"}, - {sdk.NewDecWithPrec(12340, 8), "0.000123400000000000"}, - {sdk.NewDecWithPrec(1009009009009009009, 17), "10.090090090090090090"}, - } - for tcIndex, tc := range tests { - s.Require().Equal(tc.want, tc.d.String(), "bad String(), index: %v", tcIndex) - } -} - -func (s *decimalTestSuite) TestDecFloat64() { - tests := []struct { - d sdk.Dec - want float64 - }{ - {sdk.NewDec(0), 0.000000000000000000}, - {sdk.NewDec(1), 1.000000000000000000}, - {sdk.NewDec(10), 10.000000000000000000}, - {sdk.NewDec(12340), 12340.000000000000000000}, - {sdk.NewDecWithPrec(12340, 4), 1.234000000000000000}, - {sdk.NewDecWithPrec(12340, 5), 0.123400000000000000}, - {sdk.NewDecWithPrec(12340, 8), 0.000123400000000000}, - {sdk.NewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, - } - for tcIndex, tc := range tests { - value, err := tc.d.Float64() - s.Require().Nil(err, "error getting Float64(), index: %v", tcIndex) - s.Require().Equal(tc.want, value, "bad Float64(), index: %v", tcIndex) - s.Require().Equal(tc.want, tc.d.MustFloat64(), "bad MustFloat64(), index: %v", tcIndex) - } -} - -func (s *decimalTestSuite) TestEqualities() { - tests := []struct { - d1, d2 sdk.Dec - gt, lt, eq bool - }{ - {sdk.NewDec(0), sdk.NewDec(0), false, false, true}, - {sdk.NewDecWithPrec(0, 2), sdk.NewDecWithPrec(0, 4), false, false, true}, - {sdk.NewDecWithPrec(100, 0), sdk.NewDecWithPrec(100, 0), false, false, true}, - {sdk.NewDecWithPrec(-100, 0), sdk.NewDecWithPrec(-100, 0), false, false, true}, - {sdk.NewDecWithPrec(-1, 1), sdk.NewDecWithPrec(-1, 1), false, false, true}, - {sdk.NewDecWithPrec(3333, 3), sdk.NewDecWithPrec(3333, 3), false, false, true}, - - {sdk.NewDecWithPrec(0, 0), sdk.NewDecWithPrec(3333, 3), false, true, false}, - {sdk.NewDecWithPrec(0, 0), sdk.NewDecWithPrec(100, 0), false, true, false}, - {sdk.NewDecWithPrec(-1, 0), sdk.NewDecWithPrec(3333, 3), false, true, false}, - {sdk.NewDecWithPrec(-1, 0), sdk.NewDecWithPrec(100, 0), false, true, false}, - {sdk.NewDecWithPrec(1111, 3), sdk.NewDecWithPrec(100, 0), false, true, false}, - {sdk.NewDecWithPrec(1111, 3), sdk.NewDecWithPrec(3333, 3), false, true, false}, - {sdk.NewDecWithPrec(-3333, 3), sdk.NewDecWithPrec(-1111, 3), false, true, false}, - - {sdk.NewDecWithPrec(3333, 3), sdk.NewDecWithPrec(0, 0), true, false, false}, - {sdk.NewDecWithPrec(100, 0), sdk.NewDecWithPrec(0, 0), true, false, false}, - {sdk.NewDecWithPrec(3333, 3), sdk.NewDecWithPrec(-1, 0), true, false, false}, - {sdk.NewDecWithPrec(100, 0), sdk.NewDecWithPrec(-1, 0), true, false, false}, - {sdk.NewDecWithPrec(100, 0), sdk.NewDecWithPrec(1111, 3), true, false, false}, - {sdk.NewDecWithPrec(3333, 3), sdk.NewDecWithPrec(1111, 3), true, false, false}, - {sdk.NewDecWithPrec(-1111, 3), sdk.NewDecWithPrec(-3333, 3), true, false, false}, - } - - for tcIndex, tc := range tests { - s.Require().Equal(tc.gt, tc.d1.GT(tc.d2), "GT result is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.lt, tc.d1.LT(tc.d2), "LT result is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.eq, tc.d1.Equal(tc.d2), "equality result is incorrect, tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestDecsEqual() { - tests := []struct { - d1s, d2s []sdk.Dec - eq bool - }{ - {[]sdk.Dec{sdk.NewDec(0)}, []sdk.Dec{sdk.NewDec(0)}, true}, - {[]sdk.Dec{sdk.NewDec(0)}, []sdk.Dec{sdk.NewDec(1)}, false}, - {[]sdk.Dec{sdk.NewDec(0)}, []sdk.Dec{}, false}, - {[]sdk.Dec{sdk.NewDec(0), sdk.NewDec(1)}, []sdk.Dec{sdk.NewDec(0), sdk.NewDec(1)}, true}, - {[]sdk.Dec{sdk.NewDec(1), sdk.NewDec(0)}, []sdk.Dec{sdk.NewDec(1), sdk.NewDec(0)}, true}, - {[]sdk.Dec{sdk.NewDec(1), sdk.NewDec(0)}, []sdk.Dec{sdk.NewDec(0), sdk.NewDec(1)}, false}, - {[]sdk.Dec{sdk.NewDec(1), sdk.NewDec(0)}, []sdk.Dec{sdk.NewDec(1)}, false}, - {[]sdk.Dec{sdk.NewDec(1), sdk.NewDec(2)}, []sdk.Dec{sdk.NewDec(2), sdk.NewDec(4)}, false}, - {[]sdk.Dec{sdk.NewDec(3), sdk.NewDec(18)}, []sdk.Dec{sdk.NewDec(1), sdk.NewDec(6)}, false}, - } - - for tcIndex, tc := range tests { - s.Require().Equal(tc.eq, sdk.DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.eq, sdk.DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestArithmetic() { - tests := []struct { - d1, d2 sdk.Dec - expMul, expMulTruncate sdk.Dec - expQuo, expQuoRoundUp, expQuoTruncate sdk.Dec - expAdd, expSub sdk.Dec - }{ - // d1 d2 MUL MulTruncate QUO QUORoundUp QUOTrunctate ADD SUB - {sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0)}, - {sdk.NewDec(1), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(1), sdk.NewDec(1)}, - {sdk.NewDec(0), sdk.NewDec(1), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(1), sdk.NewDec(-1)}, - {sdk.NewDec(0), sdk.NewDec(-1), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(-1), sdk.NewDec(1)}, - {sdk.NewDec(-1), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(0), sdk.NewDec(-1), sdk.NewDec(-1)}, - - {sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(2), sdk.NewDec(0)}, - {sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(-2), sdk.NewDec(0)}, - {sdk.NewDec(1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(0), sdk.NewDec(2)}, - {sdk.NewDec(-1), sdk.NewDec(1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(-1), sdk.NewDec(0), sdk.NewDec(-2)}, - - { - sdk.NewDec(3), sdk.NewDec(7), sdk.NewDec(21), sdk.NewDec(21), - sdk.NewDecWithPrec(428571428571428571, 18), sdk.NewDecWithPrec(428571428571428572, 18), sdk.NewDecWithPrec(428571428571428571, 18), - sdk.NewDec(10), sdk.NewDec(-4), - }, - { - sdk.NewDec(2), sdk.NewDec(4), sdk.NewDec(8), sdk.NewDec(8), sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(5, 1), - sdk.NewDec(6), sdk.NewDec(-2), - }, - - {sdk.NewDec(100), sdk.NewDec(100), sdk.NewDec(10000), sdk.NewDec(10000), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(200), sdk.NewDec(0)}, - - { - sdk.NewDecWithPrec(15, 1), sdk.NewDecWithPrec(15, 1), sdk.NewDecWithPrec(225, 2), sdk.NewDecWithPrec(225, 2), - sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(1), sdk.NewDec(3), sdk.NewDec(0), - }, - { - sdk.NewDecWithPrec(3333, 4), sdk.NewDecWithPrec(333, 4), sdk.NewDecWithPrec(1109889, 8), sdk.NewDecWithPrec(1109889, 8), - sdk.MustNewDecFromStr("10.009009009009009009"), sdk.MustNewDecFromStr("10.009009009009009010"), sdk.MustNewDecFromStr("10.009009009009009009"), - sdk.NewDecWithPrec(3666, 4), sdk.NewDecWithPrec(3, 1), - }, - } - - for tcIndex, tc := range tests { - tc := tc - resAdd := tc.d1.Add(tc.d2) - resSub := tc.d1.Sub(tc.d2) - resMul := tc.d1.Mul(tc.d2) - resMulTruncate := tc.d1.MulTruncate(tc.d2) - s.Require().True(tc.expAdd.Equal(resAdd), "exp %v, res %v, tc %d", tc.expAdd, resAdd, tcIndex) - s.Require().True(tc.expSub.Equal(resSub), "exp %v, res %v, tc %d", tc.expSub, resSub, tcIndex) - s.Require().True(tc.expMul.Equal(resMul), "exp %v, res %v, tc %d", tc.expMul, resMul, tcIndex) - s.Require().True(tc.expMulTruncate.Equal(resMulTruncate), "exp %v, res %v, tc %d", tc.expMulTruncate, resMulTruncate, tcIndex) - - if tc.d2.IsZero() { // panic for divide by zero - s.Require().Panics(func() { tc.d1.Quo(tc.d2) }) - } else { - resQuo := tc.d1.Quo(tc.d2) - s.Require().True(tc.expQuo.Equal(resQuo), "exp %v, res %v, tc %d", tc.expQuo.String(), resQuo.String(), tcIndex) - - resQuoRoundUp := tc.d1.QuoRoundUp(tc.d2) - s.Require().True(tc.expQuoRoundUp.Equal(resQuoRoundUp), "exp %v, res %v, tc %d", - tc.expQuoRoundUp.String(), resQuoRoundUp.String(), tcIndex) - - resQuoTruncate := tc.d1.QuoTruncate(tc.d2) - s.Require().True(tc.expQuoTruncate.Equal(resQuoTruncate), "exp %v, res %v, tc %d", - tc.expQuoTruncate.String(), resQuoTruncate.String(), tcIndex) - } - } -} - -func (s *decimalTestSuite) TestBankerRoundChop() { - tests := []struct { - d1 sdk.Dec - exp int64 - }{ - {s.mustNewDecFromStr("0.25"), 0}, - {s.mustNewDecFromStr("0"), 0}, - {s.mustNewDecFromStr("1"), 1}, - {s.mustNewDecFromStr("0.75"), 1}, - {s.mustNewDecFromStr("0.5"), 0}, - {s.mustNewDecFromStr("7.5"), 8}, - {s.mustNewDecFromStr("1.5"), 2}, - {s.mustNewDecFromStr("2.5"), 2}, - {s.mustNewDecFromStr("0.545"), 1}, // 0.545-> 1 even though 5 is first decimal and 1 not even - {s.mustNewDecFromStr("1.545"), 2}, - } - - for tcIndex, tc := range tests { - resNeg := tc.d1.Neg().RoundInt64() - s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) - - resPos := tc.d1.RoundInt64() - s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestTruncate() { - tests := []struct { - d1 sdk.Dec - exp int64 - }{ - {s.mustNewDecFromStr("0"), 0}, - {s.mustNewDecFromStr("0.25"), 0}, - {s.mustNewDecFromStr("0.75"), 0}, - {s.mustNewDecFromStr("1"), 1}, - {s.mustNewDecFromStr("1.5"), 1}, - {s.mustNewDecFromStr("7.5"), 7}, - {s.mustNewDecFromStr("7.6"), 7}, - {s.mustNewDecFromStr("7.4"), 7}, - {s.mustNewDecFromStr("100.1"), 100}, - {s.mustNewDecFromStr("1000.1"), 1000}, - } - - for tcIndex, tc := range tests { - resNeg := tc.d1.Neg().TruncateInt64() - s.Require().Equal(-1*tc.exp, resNeg, "negative tc %d", tcIndex) - - resPos := tc.d1.TruncateInt64() - s.Require().Equal(tc.exp, resPos, "positive tc %d", tcIndex) - } -} - -func (s *decimalTestSuite) TestStringOverflow() { - // two random 64 bit primes - dec1, err := sdk.NewDecFromStr("51643150036226787134389711697696177267") - s.Require().NoError(err) - dec2, err := sdk.NewDecFromStr("-31798496660535729618459429845579852627") - s.Require().NoError(err) - dec3 := dec1.Add(dec2) - s.Require().Equal( - "19844653375691057515930281852116324640.000000000000000000", - dec3.String(), - ) -} - -func (s *decimalTestSuite) TestDecMulInt() { - tests := []struct { - sdkDec sdk.Dec - sdkInt sdk.Int - want sdk.Dec - }{ - {sdk.NewDec(10), sdk.NewInt(2), sdk.NewDec(20)}, - {sdk.NewDec(1000000), sdk.NewInt(100), sdk.NewDec(100000000)}, - {sdk.NewDecWithPrec(1, 1), sdk.NewInt(10), sdk.NewDec(1)}, - {sdk.NewDecWithPrec(1, 5), sdk.NewInt(20), sdk.NewDecWithPrec(2, 4)}, - } - for i, tc := range tests { - got := tc.sdkDec.MulInt(tc.sdkInt) - s.Require().Equal(tc.want, got, "Incorrect result on test case %d", i) - } -} - -func (s *decimalTestSuite) TestDecCeil() { - testCases := []struct { - input sdk.Dec - expected sdk.Dec - }{ - {sdk.NewDecWithPrec(1000000000000000, sdk.Precision), sdk.NewDec(1)}, // 0.001 => 1.0 - {sdk.NewDecWithPrec(-1000000000000000, sdk.Precision), sdk.ZeroDec()}, // -0.001 => 0.0 - {sdk.ZeroDec(), sdk.ZeroDec()}, // 0.0 => 0.0 - {sdk.NewDecWithPrec(900000000000000000, sdk.Precision), sdk.NewDec(1)}, // 0.9 => 1.0 - {sdk.NewDecWithPrec(4001000000000000000, sdk.Precision), sdk.NewDec(5)}, // 4.001 => 5.0 - {sdk.NewDecWithPrec(-4001000000000000000, sdk.Precision), sdk.NewDec(-4)}, // -4.001 => -4.0 - {sdk.NewDecWithPrec(4700000000000000000, sdk.Precision), sdk.NewDec(5)}, // 4.7 => 5.0 - {sdk.NewDecWithPrec(-4700000000000000000, sdk.Precision), sdk.NewDec(-4)}, // -4.7 => -4.0 - } - - for i, tc := range testCases { - res := tc.input.Ceil() - s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) - } -} - -func (s *decimalTestSuite) TestPower() { - testCases := []struct { - input sdk.Dec - power uint64 - expected sdk.Dec - }{ - {sdk.NewDec(100), 0, sdk.OneDec()}, // 10 ^ (0) => 1.0 - {sdk.OneDec(), 10, sdk.OneDec()}, // 1.0 ^ (10) => 1.0 - {sdk.NewDecWithPrec(5, 1), 2, sdk.NewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 - {sdk.NewDecWithPrec(2, 1), 2, sdk.NewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 - {sdk.NewDecFromInt(sdk.NewInt(3)), 3, sdk.NewDecFromInt(sdk.NewInt(27))}, // 3 ^ 3 => 27 - {sdk.NewDecFromInt(sdk.NewInt(-3)), 4, sdk.NewDecFromInt(sdk.NewInt(81))}, // -3 ^ 4 = 81 - {sdk.NewDecWithPrec(1414213562373095049, 18), 2, sdk.NewDecFromInt(sdk.NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 - } - - for i, tc := range testCases { - res := tc.input.Power(tc.power) - s.Require().True(tc.expected.Sub(res).Abs().LTE(sdk.SmallestDec()), "unexpected result for test case %d, normal power, input: %v", i, tc.input) - - mutableInput := tc.input - mutableInput.PowerMut(tc.power) - s.Require().True(tc.expected.Sub(mutableInput).Abs().LTE(sdk.SmallestDec()), - "unexpected result for test case %d, input %v", i, tc.input) - s.Require().True(res.Equal(tc.input), "unexpected result for test case %d, mutable power, input: %v", i, tc.input) - } -} - -func (s *decimalTestSuite) TestApproxRoot() { - testCases := []struct { - input sdk.Dec - root uint64 - expected sdk.Dec - }{ - {sdk.OneDec(), 10, sdk.OneDec()}, // 1.0 ^ (0.1) => 1.0 - {sdk.NewDecWithPrec(25, 2), 2, sdk.NewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 - {sdk.NewDecWithPrec(4, 2), 2, sdk.NewDecWithPrec(2, 1)}, // 0.04 ^ (0.5) => 0.2 - {sdk.NewDecFromInt(sdk.NewInt(27)), 3, sdk.NewDecFromInt(sdk.NewInt(3))}, // 27 ^ (1/3) => 3 - {sdk.NewDecFromInt(sdk.NewInt(-81)), 4, sdk.NewDecFromInt(sdk.NewInt(-3))}, // -81 ^ (0.25) => -3 - {sdk.NewDecFromInt(sdk.NewInt(2)), 2, sdk.NewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 - {sdk.NewDecWithPrec(1005, 3), 31536000, sdk.MustNewDecFromStr("1.000000000158153904")}, // 1.005 ^ (1/31536000) ≈ 1.00000000016 - {sdk.SmallestDec(), 2, sdk.NewDecWithPrec(1, 9)}, // 1e-18 ^ (0.5) => 1e-9 - {sdk.SmallestDec(), 3, sdk.MustNewDecFromStr("0.000000999999999997")}, // 1e-18 ^ (1/3) => 1e-6 - {sdk.NewDecWithPrec(1, 8), 3, sdk.MustNewDecFromStr("0.002154434690031900")}, // 1e-8 ^ (1/3) ≈ 0.00215443469 - {sdk.MustNewDecFromStr("9000002314687921634000000000000000000021394871242000000000000000"), 2, sdk.MustNewDecFromStr("94868342004527103646332858502867.899477053226766107")}, - } - - // In the case of 1e-8 ^ (1/3), the result repeats every 5 iterations starting from iteration 24 - // (i.e. 24, 29, 34, ... give the same result) and never converges enough. The maximum number of - // iterations (300) causes the result at iteration 300 to be returned, regardless of convergence. - - for i, tc := range testCases { - res, err := tc.input.ApproxRoot(tc.root) - s.Require().NoError(err) - s.Require().True(tc.expected.Sub(res).Abs().LTE(sdk.SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) - } -} - -func (s *decimalTestSuite) TestApproxSqrt() { - testCases := []struct { - input sdk.Dec - expected sdk.Dec - }{ - {sdk.OneDec(), sdk.OneDec()}, // 1.0 => 1.0 - {sdk.NewDecWithPrec(25, 2), sdk.NewDecWithPrec(5, 1)}, // 0.25 => 0.5 - {sdk.NewDecWithPrec(4, 2), sdk.NewDecWithPrec(2, 1)}, // 0.09 => 0.3 - {sdk.NewDecFromInt(sdk.NewInt(9)), sdk.NewDecFromInt(sdk.NewInt(3))}, // 9 => 3 - {sdk.NewDecFromInt(sdk.NewInt(-9)), sdk.NewDecFromInt(sdk.NewInt(-3))}, // -9 => -3 - {sdk.NewDecFromInt(sdk.NewInt(2)), sdk.NewDecWithPrec(1414213562373095049, 18)}, // 2 => 1.414213562373095049 - } - - for i, tc := range testCases { - res, err := tc.input.ApproxSqrt() - s.Require().NoError(err) - s.Require().Equal(tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) - } -} - -func (s *decimalTestSuite) TestDecSortableBytes() { - tests := []struct { - d sdk.Dec - want []byte - }{ - {sdk.NewDec(0), []byte("000000000000000000.000000000000000000")}, - {sdk.NewDec(1), []byte("000000000000000001.000000000000000000")}, - {sdk.NewDec(10), []byte("000000000000000010.000000000000000000")}, - {sdk.NewDec(12340), []byte("000000000000012340.000000000000000000")}, - {sdk.NewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, - {sdk.NewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, - {sdk.NewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, - {sdk.NewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, - {sdk.NewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, - {sdk.NewDec(1000000000000000000), []byte("max")}, - {sdk.NewDec(-1000000000000000000), []byte("--")}, - } - for tcIndex, tc := range tests { - s.Require().Equal(tc.want, sdk.SortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) - } - - s.Require().Panics(func() { sdk.SortableDecBytes(sdk.NewDec(1000000000000000001)) }) - s.Require().Panics(func() { sdk.SortableDecBytes(sdk.NewDec(-1000000000000000001)) }) -} - -func (s *decimalTestSuite) TestDecEncoding() { - largestBigInt, ok := new(big.Int).SetString("33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) - s.Require().True(ok) - - smallestBigInt, ok := new(big.Int).SetString("-33499189745056880149688856635597007162669032647290798121690100488888732861290034376435130433535", 10) - s.Require().True(ok) - - const maxDecBitLen = 315 - maxInt, ok := new(big.Int).SetString(strings.Repeat("1", maxDecBitLen), 2) - s.Require().True(ok) - - testCases := []struct { - input sdk.Dec - rawBz string - jsonStr string - yamlStr string - }{ - { - sdk.NewDec(0), "30", - "\"0.000000000000000000\"", - "\"0.000000000000000000\"\n", - }, - { - sdk.NewDecWithPrec(4, 2), - "3430303030303030303030303030303030", - "\"0.040000000000000000\"", - "\"0.040000000000000000\"\n", - }, - { - sdk.NewDecWithPrec(-4, 2), - "2D3430303030303030303030303030303030", - "\"-0.040000000000000000\"", - "\"-0.040000000000000000\"\n", - }, - { - sdk.NewDecWithPrec(1414213562373095049, 18), - "31343134323133353632333733303935303439", - "\"1.414213562373095049\"", - "\"1.414213562373095049\"\n", - }, - { - sdk.NewDecWithPrec(-1414213562373095049, 18), - "2D31343134323133353632333733303935303439", - "\"-1.414213562373095049\"", - "\"-1.414213562373095049\"\n", - }, - { - sdk.NewDecFromBigIntWithPrec(largestBigInt, 18), - "3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", - "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", - "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", - }, - { - sdk.NewDecFromBigIntWithPrec(smallestBigInt, 18), - "2D3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", - "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", - "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", - }, - { - sdk.NewDecFromBigIntWithPrec(maxInt, 18), - "3636373439353934383732353238343430303734383434343238333137373938353033353831333334353136333233363435333939303630383435303530323434343434333636343330363435303137313838323137353635323136373637", - "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"", - "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"\n", - }, - } - - for _, tc := range testCases { - bz, err := tc.input.Marshal() - s.Require().NoError(err) - s.Require().Equal(tc.rawBz, fmt.Sprintf("%X", bz)) - - var other sdk.Dec - s.Require().NoError((&other).Unmarshal(bz)) - s.Require().True(tc.input.Equal(other)) - - bz, err = json.Marshal(tc.input) - s.Require().NoError(err) - s.Require().Equal(tc.jsonStr, string(bz)) - s.Require().NoError(json.Unmarshal(bz, &other)) - s.Require().True(tc.input.Equal(other)) - - bz, err = yaml.Marshal(tc.input) - s.Require().NoError(err) - s.Require().Equal(tc.yamlStr, string(bz)) - } -} - -// Showcase that different orders of operations causes different results. -func (s *decimalTestSuite) TestOperationOrders() { - n1 := sdk.NewDec(10) - n2 := sdk.NewDec(1000000010) - s.Require().Equal(n1.Mul(n2).Quo(n2), sdk.NewDec(10)) - s.Require().NotEqual(n1.Mul(n2).Quo(n2), n1.Quo(n2).Mul(n2)) -} - -func BenchmarkMarshalTo(b *testing.B) { - b.ReportAllocs() - bis := []struct { - in sdk.Dec - want []byte - }{ - { - sdk.NewDec(1e8), []byte{ - 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - }, - }, - {sdk.NewDec(0), []byte{0x30}}, - } - data := make([]byte, 100) - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - for _, bi := range bis { - if n, err := bi.in.MarshalTo(data); err != nil { - b.Fatal(err) - } else { - if !bytes.Equal(data[:n], bi.want) { - b.Fatalf("Mismatch\nGot: % x\nWant: % x\n", data[:n], bi.want) - } - } - } - } -} diff --git a/types/math.go b/types/math.go index be46b0591677..ff72dd9550c9 100644 --- a/types/math.go +++ b/types/math.go @@ -35,3 +35,36 @@ const ( func (ip IntProto) String() string { return ip.Int.String() } + +var _ CustomProtobufType = (*Dec)(nil) + +type ( + Dec = sdkmath.Dec +) + +const ( + Precision = sdkmath.Precision + DecimalPrecisionBits = sdkmath.DecimalPrecisionBits +) + +var ( + ZeroDec = sdkmath.ZeroDec + OneDec = sdkmath.OneDec + SmallestDec = sdkmath.SmallestDec + NewDec = sdkmath.NewDec + NewDecWithPrec = sdkmath.NewDecWithPrec + NewDecFromBigInt = sdkmath.NewDecFromBigInt + NewDecFromBigIntWithPrec = sdkmath.NewDecFromBigIntWithPrec + NewDecFromInt = sdkmath.NewDecFromInt + NewDecFromIntWithPrec = sdkmath.NewDecFromIntWithPrec + NewDecFromStr = sdkmath.NewDecFromStr + MustNewDecFromStr = sdkmath.MustNewDecFromStr + MaxSortableDec = sdkmath.MaxSortableDec + ValidSortableDec = sdkmath.ValidSortableDec + SortableDecBytes = sdkmath.SortableDecBytes + DecsEqual = sdkmath.DecsEqual + MinDec = sdkmath.MinDec + MaxDec = sdkmath.MaxDec + DecEq = sdkmath.DecEq + DecApproxEq = sdkmath.DecApproxEq +) From ad92d18c5480878cdc05115300c70ff51578e217 Mon Sep 17 00:00:00 2001 From: Amaury M <1293565+amaurym@users.noreply.github.com> Date: Tue, 19 Jul 2022 17:19:08 +0200 Subject: [PATCH 2/6] go mod tidy --- go.sum | 2 -- 1 file changed, 2 deletions(-) diff --git a/go.sum b/go.sum index fa3ee4671236..e8c4fab21387 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,6 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= -cosmossdk.io/math v1.0.0-beta.2 h1:17hSVc9ne1c31IaLDfjRojtN+y4Rd2N8H/6Fht2sBzw= -cosmossdk.io/math v1.0.0-beta.2/go.mod h1:u/MXvf8wbUbCsAEyQSSYXXMsczAsFX48e2D6JI86T4o= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= From de56c1aee9be7e849f2e1cc2e27ea74a90dfe187 Mon Sep 17 00:00:00 2001 From: Amaury M <1293565+amaurym@users.noreply.github.com> Date: Tue, 19 Jul 2022 17:21:16 +0200 Subject: [PATCH 3/6] changelog --- math/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/math/CHANGELOG.md b/math/CHANGELOG.md index 16de809f2717..4d9cc7a11f20 100644 --- a/math/CHANGELOG.md +++ b/math/CHANGELOG.md @@ -30,3 +30,5 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Changelog ## [Unreleased] + +* [#12634](https://github.com/cosmos/cosmos-sdk/pull/12634) Move `sdk.Dec` to math package. From 5f70ffc52dada556aa583d77ea8f8b099809b705 Mon Sep 17 00:00:00 2001 From: Amaury M <1293565+amaurym@users.noreply.github.com> Date: Tue, 19 Jul 2022 17:23:47 +0200 Subject: [PATCH 4/6] Move to math.go --- types/decimal.go | 5 ----- types/math.go | 8 ++++++-- 2 files changed, 6 insertions(+), 7 deletions(-) delete mode 100644 types/decimal.go diff --git a/types/decimal.go b/types/decimal.go deleted file mode 100644 index f7be3ad4a2ca..000000000000 --- a/types/decimal.go +++ /dev/null @@ -1,5 +0,0 @@ -package types - -func (dp DecProto) String() string { - return dp.Dec.String() -} diff --git a/types/math.go b/types/math.go index ff72dd9550c9..18cbda5695c6 100644 --- a/types/math.go +++ b/types/math.go @@ -36,8 +36,6 @@ func (ip IntProto) String() string { return ip.Int.String() } -var _ CustomProtobufType = (*Dec)(nil) - type ( Dec = sdkmath.Dec ) @@ -68,3 +66,9 @@ var ( DecEq = sdkmath.DecEq DecApproxEq = sdkmath.DecApproxEq ) + +var _ CustomProtobufType = (*Dec)(nil) + +func (dp DecProto) String() string { + return dp.Dec.String() +} From 3539ae515df31110b32aded27b9f8b339d8d1396 Mon Sep 17 00:00:00 2001 From: Amaury M <1293565+amaurym@users.noreply.github.com> Date: Wed, 20 Jul 2022 11:13:34 +0200 Subject: [PATCH 5/6] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e6677cd6c08..49abca34ab03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Improvements +* [#12634](https://github.com/cosmos/cosmos-sdk/pull/12634) Move `sdk.Dec` to math package. * [#12596](https://github.com/cosmos/cosmos-sdk/pull/12596) Remove all imports of the non-existent gogo/protobuf v1.3.3 to ease downstream use and go workspaces. * [#12589](https://github.com/cosmos/cosmos-sdk/pull/12589) Allow zero gas in simulation mode. * [#12576](https://github.com/cosmos/cosmos-sdk/pull/12576) Remove dependency on cosmos/keyring and upgrade to 99designs/keyring v1.2.1 From 7304e08c81cfd1004cd428d90966b9b26d447cf2 Mon Sep 17 00:00:00 2001 From: Amaury M <1293565+amaurym@users.noreply.github.com> Date: Wed, 20 Jul 2022 11:40:42 +0200 Subject: [PATCH 6/6] Call everything LegacyDec --- math/CHANGELOG.md | 2 +- math/dec.go | 302 ++++++++++++++--------------- math/dec_internal_test.go | 22 +-- math/dec_test.go | 398 +++++++++++++++++++------------------- types/math.go | 44 ++--- 5 files changed, 384 insertions(+), 384 deletions(-) diff --git a/math/CHANGELOG.md b/math/CHANGELOG.md index 4d9cc7a11f20..4354b122f63a 100644 --- a/math/CHANGELOG.md +++ b/math/CHANGELOG.md @@ -31,4 +31,4 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] -* [#12634](https://github.com/cosmos/cosmos-sdk/pull/12634) Move `sdk.Dec` to math package. +* [#12634](https://github.com/cosmos/cosmos-sdk/pull/12634) Move `sdk.Dec` to math package, call it `LegacyDec`. diff --git a/math/dec.go b/math/dec.go index e4239102bd65..667bfec50bdc 100644 --- a/math/dec.go +++ b/math/dec.go @@ -12,22 +12,22 @@ import ( // NOTE: never use new(Dec) or else we will panic unmarshalling into the // nil embedded big.Int -type Dec struct { +type LegacyDec struct { i *big.Int } const ( // number of decimal places - Precision = 18 + LegacyPrecision = 18 // bits required to represent the above precision // Ceiling[Log2[10^Precision - 1]] - DecimalPrecisionBits = 60 + LegacyDecimalPrecisionBits = 60 // decimalTruncateBits is the minimum number of bits removed // by a truncate operation. It is equal to // Floor[Log2[10^Precision - 1]]. - decimalTruncateBits = DecimalPrecisionBits - 1 + decimalTruncateBits = LegacyDecimalPrecisionBits - 1 maxDecBitLen = MaxBitLen + decimalTruncateBits @@ -36,7 +36,7 @@ const ( ) var ( - precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(Precision), nil) + precisionReuse = new(big.Int).Exp(big.NewInt(10), big.NewInt(LegacyPrecision), nil) fivePrecision = new(big.Int).Quo(precisionReuse, big.NewInt(2)) precisionMultipliers []*big.Int zeroInt = big.NewInt(0) @@ -46,15 +46,15 @@ var ( // Decimal errors var ( - ErrEmptyDecimalStr = errors.New("decimal string cannot be empty") - ErrInvalidDecimalLength = errors.New("invalid decimal length") - ErrInvalidDecimalStr = errors.New("invalid decimal string") + ErrLegacyEmptyDecimalStr = errors.New("decimal string cannot be empty") + ErrLegacyInvalidDecimalLength = errors.New("invalid decimal length") + ErrLegacyInvalidDecimalStr = errors.New("invalid decimal string") ) // Set precision multipliers func init() { - precisionMultipliers = make([]*big.Int, Precision+1) - for i := 0; i <= Precision; i++ { + precisionMultipliers = make([]*big.Int, LegacyPrecision+1) + for i := 0; i <= LegacyPrecision; i++ { precisionMultipliers[i] = calcPrecisionMultiplier(int64(i)) } } @@ -63,65 +63,65 @@ func precisionInt() *big.Int { return new(big.Int).Set(precisionReuse) } -func ZeroDec() Dec { return Dec{new(big.Int).Set(zeroInt)} } -func OneDec() Dec { return Dec{precisionInt()} } -func SmallestDec() Dec { return Dec{new(big.Int).Set(oneInt)} } +func LegacyZeroDec() LegacyDec { return LegacyDec{new(big.Int).Set(zeroInt)} } +func LegacyOneDec() LegacyDec { return LegacyDec{precisionInt()} } +func LegacySmallestDec() LegacyDec { return LegacyDec{new(big.Int).Set(oneInt)} } // calculate the precision multiplier func calcPrecisionMultiplier(prec int64) *big.Int { - if prec > Precision { - panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) + if prec > LegacyPrecision { + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", LegacyPrecision, prec)) } - zerosToAdd := Precision - prec + zerosToAdd := LegacyPrecision - prec multiplier := new(big.Int).Exp(tenInt, big.NewInt(zerosToAdd), nil) return multiplier } // get the precision multiplier, do not mutate result func precisionMultiplier(prec int64) *big.Int { - if prec > Precision { - panic(fmt.Sprintf("too much precision, maximum %v, provided %v", Precision, prec)) + if prec > LegacyPrecision { + panic(fmt.Sprintf("too much precision, maximum %v, provided %v", LegacyPrecision, prec)) } return precisionMultipliers[prec] } // create a new Dec from integer assuming whole number -func NewDec(i int64) Dec { - return NewDecWithPrec(i, 0) +func LegacyNewDec(i int64) LegacyDec { + return LegacyNewDecWithPrec(i, 0) } // create a new Dec from integer with decimal place at prec // CONTRACT: prec <= Precision -func NewDecWithPrec(i, prec int64) Dec { - return Dec{ +func LegacyNewDecWithPrec(i, prec int64) LegacyDec { + return LegacyDec{ new(big.Int).Mul(big.NewInt(i), precisionMultiplier(prec)), } } // create a new Dec from big integer assuming whole numbers // CONTRACT: prec <= Precision -func NewDecFromBigInt(i *big.Int) Dec { - return NewDecFromBigIntWithPrec(i, 0) +func LegacyNewDecFromBigInt(i *big.Int) LegacyDec { + return LegacyNewDecFromBigIntWithPrec(i, 0) } // create a new Dec from big integer assuming whole numbers // CONTRACT: prec <= Precision -func NewDecFromBigIntWithPrec(i *big.Int, prec int64) Dec { - return Dec{ +func LegacyNewDecFromBigIntWithPrec(i *big.Int, prec int64) LegacyDec { + return LegacyDec{ new(big.Int).Mul(i, precisionMultiplier(prec)), } } // create a new Dec from big integer assuming whole numbers // CONTRACT: prec <= Precision -func NewDecFromInt(i Int) Dec { - return NewDecFromIntWithPrec(i, 0) +func LegacyNewDecFromInt(i Int) LegacyDec { + return LegacyNewDecFromIntWithPrec(i, 0) } // create a new Dec from big integer with decimal place at prec // CONTRACT: prec <= Precision -func NewDecFromIntWithPrec(i Int, prec int64) Dec { - return Dec{ +func LegacyNewDecFromIntWithPrec(i Int, prec int64) LegacyDec { + return LegacyDec{ new(big.Int).Mul(i.BigInt(), precisionMultiplier(prec)), } } @@ -139,9 +139,9 @@ func NewDecFromIntWithPrec(i Int, prec int64) Dec { // are provided in the string than the constant Precision. // // CONTRACT - This function does not mutate the input str. -func NewDecFromStr(str string) (Dec, error) { +func LegacyNewDecFromStr(str string) (LegacyDec, error) { if len(str) == 0 { - return Dec{}, fmt.Errorf("%s: %w", str, ErrEmptyDecimalStr) + return LegacyDec{}, fmt.Errorf("%s: %w", str, ErrLegacyEmptyDecimalStr) } // first extract any negative symbol @@ -152,7 +152,7 @@ func NewDecFromStr(str string) (Dec, error) { } if len(str) == 0 { - return Dec{}, fmt.Errorf("%s: %w", str, ErrEmptyDecimalStr) + return LegacyDec{}, fmt.Errorf("%s: %w", str, ErrLegacyEmptyDecimalStr) } strs := strings.Split(str, ".") @@ -162,62 +162,62 @@ func NewDecFromStr(str string) (Dec, error) { if len(strs) == 2 { // has a decimal place lenDecs = len(strs[1]) if lenDecs == 0 || len(combinedStr) == 0 { - return Dec{}, ErrInvalidDecimalLength + return LegacyDec{}, ErrLegacyInvalidDecimalLength } combinedStr += strs[1] } else if len(strs) > 2 { - return Dec{}, ErrInvalidDecimalStr + return LegacyDec{}, ErrLegacyInvalidDecimalStr } - if lenDecs > Precision { - return Dec{}, fmt.Errorf("value '%s' exceeds max precision by %d decimal places: max precision %d", str, Precision-lenDecs, Precision) + if lenDecs > LegacyPrecision { + return LegacyDec{}, fmt.Errorf("value '%s' exceeds max precision by %d decimal places: max precision %d", str, LegacyPrecision-lenDecs, LegacyPrecision) } // add some extra zero's to correct to the Precision factor - zerosToAdd := Precision - lenDecs + zerosToAdd := LegacyPrecision - lenDecs zeros := fmt.Sprintf(`%0`+strconv.Itoa(zerosToAdd)+`s`, "") combinedStr += zeros combined, ok := new(big.Int).SetString(combinedStr, 10) // base 10 if !ok { - return Dec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr) + return LegacyDec{}, fmt.Errorf("failed to set decimal string with base 10: %s", combinedStr) } if combined.BitLen() > maxDecBitLen { - return Dec{}, fmt.Errorf("decimal '%s' out of range; bitLen: got %d, max %d", str, combined.BitLen(), maxDecBitLen) + return LegacyDec{}, fmt.Errorf("decimal '%s' out of range; bitLen: got %d, max %d", str, combined.BitLen(), maxDecBitLen) } if neg { combined = new(big.Int).Neg(combined) } - return Dec{combined}, nil + return LegacyDec{combined}, nil } // Decimal from string, panic on error -func MustNewDecFromStr(s string) Dec { - dec, err := NewDecFromStr(s) +func LegacyMustNewDecFromStr(s string) LegacyDec { + dec, err := LegacyNewDecFromStr(s) if err != nil { panic(err) } return dec } -func (d Dec) IsNil() bool { return d.i == nil } // is decimal nil -func (d Dec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero -func (d Dec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative -func (d Dec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive -func (d Dec) Equal(d2 Dec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals -func (d Dec) GT(d2 Dec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than -func (d Dec) GTE(d2 Dec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal -func (d Dec) LT(d2 Dec) bool { return (d.i).Cmp(d2.i) < 0 } // less than -func (d Dec) LTE(d2 Dec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal -func (d Dec) Neg() Dec { return Dec{new(big.Int).Neg(d.i)} } // reverse the decimal sign -func (d Dec) NegMut() Dec { d.i.Neg(d.i); return d } // reverse the decimal sign, mutable -func (d Dec) Abs() Dec { return Dec{new(big.Int).Abs(d.i)} } // absolute value -func (d Dec) Set(d2 Dec) Dec { d.i.Set(d2.i); return d } // set to existing dec value -func (d Dec) Clone() Dec { return Dec{new(big.Int).Set(d.i)} } // clone new dec +func (d LegacyDec) IsNil() bool { return d.i == nil } // is decimal nil +func (d LegacyDec) IsZero() bool { return (d.i).Sign() == 0 } // is equal to zero +func (d LegacyDec) IsNegative() bool { return (d.i).Sign() == -1 } // is negative +func (d LegacyDec) IsPositive() bool { return (d.i).Sign() == 1 } // is positive +func (d LegacyDec) Equal(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) == 0 } // equal decimals +func (d LegacyDec) GT(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) > 0 } // greater than +func (d LegacyDec) GTE(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) >= 0 } // greater than or equal +func (d LegacyDec) LT(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) < 0 } // less than +func (d LegacyDec) LTE(d2 LegacyDec) bool { return (d.i).Cmp(d2.i) <= 0 } // less than or equal +func (d LegacyDec) Neg() LegacyDec { return LegacyDec{new(big.Int).Neg(d.i)} } // reverse the decimal sign +func (d LegacyDec) NegMut() LegacyDec { d.i.Neg(d.i); return d } // reverse the decimal sign, mutable +func (d LegacyDec) Abs() LegacyDec { return LegacyDec{new(big.Int).Abs(d.i)} } // absolute value +func (d LegacyDec) Set(d2 LegacyDec) LegacyDec { d.i.Set(d2.i); return d } // set to existing dec value +func (d LegacyDec) Clone() LegacyDec { return LegacyDec{new(big.Int).Set(d.i)} } // clone new dec // BigInt returns a copy of the underlying big.Int. -func (d Dec) BigInt() *big.Int { +func (d LegacyDec) BigInt() *big.Int { if d.IsNil() { return nil } @@ -226,34 +226,34 @@ func (d Dec) BigInt() *big.Int { return cp.Set(d.i) } -func (d Dec) ImmutOp(op func(Dec, Dec) Dec, d2 Dec) Dec { +func (d LegacyDec) ImmutOp(op func(LegacyDec, LegacyDec) LegacyDec, d2 LegacyDec) LegacyDec { return op(d.Clone(), d2) } -func (d Dec) ImmutOpInt(op func(Dec, Int) Dec, d2 Int) Dec { +func (d LegacyDec) ImmutOpInt(op func(LegacyDec, Int) LegacyDec, d2 Int) LegacyDec { return op(d.Clone(), d2) } -func (d Dec) ImmutOpInt64(op func(Dec, int64) Dec, d2 int64) Dec { +func (d LegacyDec) ImmutOpInt64(op func(LegacyDec, int64) LegacyDec, d2 int64) LegacyDec { // TODO: use already allocated operand bigint to avoid // newint each time, add mutex for race condition // Issue: https://github.com/cosmos/cosmos-sdk/issues/11166 return op(d.Clone(), d2) } -func (d Dec) SetInt64(i int64) Dec { +func (d LegacyDec) SetInt64(i int64) LegacyDec { d.i.SetInt64(i) d.i.Mul(d.i, precisionReuse) return d } // addition -func (d Dec) Add(d2 Dec) Dec { - return d.ImmutOp(Dec.AddMut, d2) +func (d LegacyDec) Add(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.AddMut, d2) } // mutable addition -func (d Dec) AddMut(d2 Dec) Dec { +func (d LegacyDec) AddMut(d2 LegacyDec) LegacyDec { d.i.Add(d.i, d2.i) if d.i.BitLen() > maxDecBitLen { @@ -263,12 +263,12 @@ func (d Dec) AddMut(d2 Dec) Dec { } // subtraction -func (d Dec) Sub(d2 Dec) Dec { - return d.ImmutOp(Dec.SubMut, d2) +func (d LegacyDec) Sub(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.SubMut, d2) } // mutable subtraction -func (d Dec) SubMut(d2 Dec) Dec { +func (d LegacyDec) SubMut(d2 LegacyDec) LegacyDec { d.i.Sub(d.i, d2.i) if d.i.BitLen() > maxDecBitLen { @@ -278,12 +278,12 @@ func (d Dec) SubMut(d2 Dec) Dec { } // multiplication -func (d Dec) Mul(d2 Dec) Dec { - return d.ImmutOp(Dec.MulMut, d2) +func (d LegacyDec) Mul(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.MulMut, d2) } // mutable multiplication -func (d Dec) MulMut(d2 Dec) Dec { +func (d LegacyDec) MulMut(d2 LegacyDec) LegacyDec { d.i.Mul(d.i, d2.i) chopped := chopPrecisionAndRound(d.i) @@ -295,12 +295,12 @@ func (d Dec) MulMut(d2 Dec) Dec { } // multiplication truncate -func (d Dec) MulTruncate(d2 Dec) Dec { - return d.ImmutOp(Dec.MulTruncateMut, d2) +func (d LegacyDec) MulTruncate(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.MulTruncateMut, d2) } // mutable multiplication truncage -func (d Dec) MulTruncateMut(d2 Dec) Dec { +func (d LegacyDec) MulTruncateMut(d2 LegacyDec) LegacyDec { d.i.Mul(d.i, d2.i) chopPrecisionAndTruncate(d.i) @@ -311,11 +311,11 @@ func (d Dec) MulTruncateMut(d2 Dec) Dec { } // multiplication -func (d Dec) MulInt(i Int) Dec { - return d.ImmutOpInt(Dec.MulIntMut, i) +func (d LegacyDec) MulInt(i Int) LegacyDec { + return d.ImmutOpInt(LegacyDec.MulIntMut, i) } -func (d Dec) MulIntMut(i Int) Dec { +func (d LegacyDec) MulIntMut(i Int) LegacyDec { d.i.Mul(d.i, i.BigInt()) if d.i.BitLen() > maxDecBitLen { panic("Int overflow") @@ -324,11 +324,11 @@ func (d Dec) MulIntMut(i Int) Dec { } // MulInt64 - multiplication with int64 -func (d Dec) MulInt64(i int64) Dec { - return d.ImmutOpInt64(Dec.MulInt64Mut, i) +func (d LegacyDec) MulInt64(i int64) LegacyDec { + return d.ImmutOpInt64(LegacyDec.MulInt64Mut, i) } -func (d Dec) MulInt64Mut(i int64) Dec { +func (d LegacyDec) MulInt64Mut(i int64) LegacyDec { d.i.Mul(d.i, big.NewInt(i)) if d.i.BitLen() > maxDecBitLen { @@ -338,12 +338,12 @@ func (d Dec) MulInt64Mut(i int64) Dec { } // quotient -func (d Dec) Quo(d2 Dec) Dec { - return d.ImmutOp(Dec.QuoMut, d2) +func (d LegacyDec) Quo(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.QuoMut, d2) } // mutable quotient -func (d Dec) QuoMut(d2 Dec) Dec { +func (d LegacyDec) QuoMut(d2 LegacyDec) LegacyDec { // multiply precision twice d.i.Mul(d.i, precisionReuse) d.i.Mul(d.i, precisionReuse) @@ -357,12 +357,12 @@ func (d Dec) QuoMut(d2 Dec) Dec { } // quotient truncate -func (d Dec) QuoTruncate(d2 Dec) Dec { - return d.ImmutOp(Dec.QuoTruncateMut, d2) +func (d LegacyDec) QuoTruncate(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.QuoTruncateMut, d2) } // mutable quotient truncate -func (d Dec) QuoTruncateMut(d2 Dec) Dec { +func (d LegacyDec) QuoTruncateMut(d2 LegacyDec) LegacyDec { // multiply precision twice d.i.Mul(d.i, precisionReuse) d.i.Mul(d.i, precisionReuse) @@ -376,12 +376,12 @@ func (d Dec) QuoTruncateMut(d2 Dec) Dec { } // quotient, round up -func (d Dec) QuoRoundUp(d2 Dec) Dec { - return d.ImmutOp(Dec.QuoRoundupMut, d2) +func (d LegacyDec) QuoRoundUp(d2 LegacyDec) LegacyDec { + return d.ImmutOp(LegacyDec.QuoRoundupMut, d2) } // mutable quotient, round up -func (d Dec) QuoRoundupMut(d2 Dec) Dec { +func (d LegacyDec) QuoRoundupMut(d2 LegacyDec) LegacyDec { // multiply precision twice d.i.Mul(d.i, precisionReuse) d.i.Mul(d.i, precisionReuse) @@ -395,21 +395,21 @@ func (d Dec) QuoRoundupMut(d2 Dec) Dec { } // quotient -func (d Dec) QuoInt(i Int) Dec { - return d.ImmutOpInt(Dec.QuoIntMut, i) +func (d LegacyDec) QuoInt(i Int) LegacyDec { + return d.ImmutOpInt(LegacyDec.QuoIntMut, i) } -func (d Dec) QuoIntMut(i Int) Dec { +func (d LegacyDec) QuoIntMut(i Int) LegacyDec { d.i.Quo(d.i, i.BigInt()) return d } // QuoInt64 - quotient with int64 -func (d Dec) QuoInt64(i int64) Dec { - return d.ImmutOpInt64(Dec.QuoInt64Mut, i) +func (d LegacyDec) QuoInt64(i int64) LegacyDec { + return d.ImmutOpInt64(LegacyDec.QuoInt64Mut, i) } -func (d Dec) QuoInt64Mut(i int64) Dec { +func (d LegacyDec) QuoInt64Mut(i int64) LegacyDec { d.i.Quo(d.i, big.NewInt(i)) return d } @@ -420,7 +420,7 @@ func (d Dec) QuoInt64Mut(i int64) Dec { // approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. // A maximum number of 100 iterations is used a backup boundary condition for // cases where the answer never converges enough to satisfy the main condition. -func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { +func (d LegacyDec) ApproxRoot(root uint64) (guess LegacyDec, err error) { defer func() { if r := recover(); r != nil { var ok bool @@ -436,20 +436,20 @@ func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { return absRoot.NegMut(), err } - if root == 1 || d.IsZero() || d.Equal(OneDec()) { + if root == 1 || d.IsZero() || d.Equal(LegacyOneDec()) { return d, nil } if root == 0 { - return OneDec(), nil + return LegacyOneDec(), nil } - guess, delta := OneDec(), OneDec() + guess, delta := LegacyOneDec(), LegacyOneDec() - for iter := 0; delta.Abs().GT(SmallestDec()) && iter < maxApproxRootIterations; iter++ { + for iter := 0; delta.Abs().GT(LegacySmallestDec()) && iter < maxApproxRootIterations; iter++ { prev := guess.Power(root - 1) if prev.IsZero() { - prev = SmallestDec() + prev = LegacySmallestDec() } delta.Set(d).QuoMut(prev) delta.SubMut(guess) @@ -462,17 +462,17 @@ func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { } // Power returns a the result of raising to a positive integer power -func (d Dec) Power(power uint64) Dec { - res := Dec{new(big.Int).Set(d.i)} +func (d LegacyDec) Power(power uint64) LegacyDec { + res := LegacyDec{new(big.Int).Set(d.i)} return res.PowerMut(power) } -func (d Dec) PowerMut(power uint64) Dec { +func (d LegacyDec) PowerMut(power uint64) LegacyDec { if power == 0 { d.SetInt64(1) return d } - tmp := OneDec() + tmp := LegacyOneDec() for i := power; i > 1; { if i%2 != 0 { @@ -487,24 +487,24 @@ func (d Dec) PowerMut(power uint64) Dec { // ApproxSqrt is a wrapper around ApproxRoot for the common special case // of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. -func (d Dec) ApproxSqrt() (Dec, error) { +func (d LegacyDec) ApproxSqrt() (LegacyDec, error) { return d.ApproxRoot(2) } // is integer, e.g. decimals are zero -func (d Dec) IsInteger() bool { +func (d LegacyDec) IsInteger() bool { return new(big.Int).Rem(d.i, precisionReuse).Sign() == 0 } // format decimal state -func (d Dec) Format(s fmt.State, verb rune) { +func (d LegacyDec) Format(s fmt.State, verb rune) { _, err := s.Write([]byte(d.String())) if err != nil { panic(err) } } -func (d Dec) String() string { +func (d LegacyDec) String() string { if d.i == nil { return d.i.String() } @@ -525,24 +525,24 @@ func (d Dec) String() string { // TODO: Remove trailing zeros // case 1, purely decimal - if inputSize <= Precision { - bzStr = make([]byte, Precision+2) + if inputSize <= LegacyPrecision { + bzStr = make([]byte, LegacyPrecision+2) // 0. prefix bzStr[0] = byte('0') bzStr[1] = byte('.') // set relevant digits to 0 - for i := 0; i < Precision-inputSize; i++ { + for i := 0; i < LegacyPrecision-inputSize; i++ { bzStr[i+2] = byte('0') } // set final digits - copy(bzStr[2+(Precision-inputSize):], bzInt) + copy(bzStr[2+(LegacyPrecision-inputSize):], bzInt) } else { // inputSize + 1 to account for the decimal point that is being added bzStr = make([]byte, inputSize+1) - decPointPlace := inputSize - Precision + decPointPlace := inputSize - LegacyPrecision copy(bzStr, bzInt[:decPointPlace]) // pre-decimal digits bzStr[decPointPlace] = byte('.') // decimal point @@ -558,13 +558,13 @@ func (d Dec) String() string { // Float64 returns the float64 representation of a Dec. // Will return the error if the conversion failed. -func (d Dec) Float64() (float64, error) { +func (d LegacyDec) Float64() (float64, error) { return strconv.ParseFloat(d.String(), 64) } // MustFloat64 returns the float64 representation of a Dec. // Would panic if the conversion failed. -func (d Dec) MustFloat64() float64 { +func (d LegacyDec) MustFloat64() float64 { if value, err := strconv.ParseFloat(d.String(), 64); err != nil { panic(err) } else { @@ -645,7 +645,7 @@ func chopPrecisionAndRoundNonMutative(d *big.Int) *big.Int { } // RoundInt64 rounds the decimal using bankers rounding -func (d Dec) RoundInt64() int64 { +func (d LegacyDec) RoundInt64() int64 { chopped := chopPrecisionAndRoundNonMutative(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") @@ -654,7 +654,7 @@ func (d Dec) RoundInt64() int64 { } // RoundInt round the decimal using bankers rounding -func (d Dec) RoundInt() Int { +func (d LegacyDec) RoundInt() Int { return NewIntFromBigInt(chopPrecisionAndRoundNonMutative(d.i)) } @@ -671,7 +671,7 @@ func chopPrecisionAndTruncateNonMutative(d *big.Int) *big.Int { } // TruncateInt64 truncates the decimals from the number and returns an int64 -func (d Dec) TruncateInt64() int64 { +func (d LegacyDec) TruncateInt64() int64 { chopped := chopPrecisionAndTruncateNonMutative(d.i) if !chopped.IsInt64() { panic("Int64() out of bound") @@ -680,18 +680,18 @@ func (d Dec) TruncateInt64() int64 { } // TruncateInt truncates the decimals from the number and returns an Int -func (d Dec) TruncateInt() Int { +func (d LegacyDec) TruncateInt() Int { return NewIntFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) } // TruncateDec truncates the decimals from the number and returns a Dec -func (d Dec) TruncateDec() Dec { - return NewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) +func (d LegacyDec) TruncateDec() LegacyDec { + return LegacyNewDecFromBigInt(chopPrecisionAndTruncateNonMutative(d.i)) } // Ceil returns the smallest interger value (as a decimal) that is greater than // or equal to the given decimal. -func (d Dec) Ceil() Dec { +func (d LegacyDec) Ceil() LegacyDec { tmp := new(big.Int).Set(d.i) quo, rem := tmp, big.NewInt(0) @@ -699,52 +699,52 @@ func (d Dec) Ceil() Dec { // no need to round with a zero remainder regardless of sign if rem.Cmp(zeroInt) == 0 { - return NewDecFromBigInt(quo) + return LegacyNewDecFromBigInt(quo) } if rem.Sign() == -1 { - return NewDecFromBigInt(quo) + return LegacyNewDecFromBigInt(quo) } - return NewDecFromBigInt(quo.Add(quo, oneInt)) + return LegacyNewDecFromBigInt(quo.Add(quo, oneInt)) } // MaxSortableDec is the largest Dec that can be passed into SortableDecBytes() // Its negative form is the least Dec that can be passed in. -var MaxSortableDec Dec +var LegacyMaxSortableDec LegacyDec func init() { - MaxSortableDec = OneDec().Quo(SmallestDec()) + LegacyMaxSortableDec = LegacyOneDec().Quo(LegacySmallestDec()) } // 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.Abs().LTE(MaxSortableDec) +func LegacyValidSortableDec(dec LegacyDec) bool { + return dec.Abs().LTE(LegacyMaxSortableDec) } // 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) { +func LegacySortableDecBytes(dec LegacyDec) []byte { + if !LegacyValidSortableDec(dec) { panic("dec must be within bounds") } // Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just // makes its bytes be "max" which comes after all numbers in ASCIIbetical order - if dec.Equal(MaxSortableDec) { + if dec.Equal(LegacyMaxSortableDec) { return []byte("max") } // For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers. - if dec.Equal(MaxSortableDec.Neg()) { + if dec.Equal(LegacyMaxSortableDec.Neg()) { return []byte("--") } // We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers if dec.IsNegative() { - return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.Abs().String()))...) + return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", LegacyPrecision*2+1), dec.Abs().String()))...) } - return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", Precision*2+1), dec.String())) + return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", LegacyPrecision*2+1), dec.String())) } // reuse nil values @@ -757,7 +757,7 @@ func init() { } // MarshalJSON marshals the decimal -func (d Dec) MarshalJSON() ([]byte, error) { +func (d LegacyDec) MarshalJSON() ([]byte, error) { if d.i == nil { return nilJSON, nil } @@ -765,7 +765,7 @@ func (d Dec) MarshalJSON() ([]byte, error) { } // UnmarshalJSON defines custom decoding scheme -func (d *Dec) UnmarshalJSON(bz []byte) error { +func (d *LegacyDec) UnmarshalJSON(bz []byte) error { if d.i == nil { d.i = new(big.Int) } @@ -777,7 +777,7 @@ func (d *Dec) UnmarshalJSON(bz []byte) error { } // TODO: Reuse dec allocation - newDec, err := NewDecFromStr(text) + newDec, err := LegacyNewDecFromStr(text) if err != nil { return err } @@ -787,12 +787,12 @@ func (d *Dec) UnmarshalJSON(bz []byte) error { } // MarshalYAML returns the YAML representation. -func (d Dec) MarshalYAML() (interface{}, error) { +func (d LegacyDec) MarshalYAML() (interface{}, error) { return d.String(), nil } // Marshal implements the gogo proto custom type interface. -func (d Dec) Marshal() ([]byte, error) { +func (d LegacyDec) Marshal() ([]byte, error) { if d.i == nil { d.i = new(big.Int) } @@ -800,7 +800,7 @@ func (d Dec) Marshal() ([]byte, error) { } // MarshalTo implements the gogo proto custom type interface. -func (d *Dec) MarshalTo(data []byte) (n int, err error) { +func (d *LegacyDec) MarshalTo(data []byte) (n int, err error) { if d.i == nil { d.i = new(big.Int) } @@ -820,7 +820,7 @@ func (d *Dec) MarshalTo(data []byte) (n int, err error) { } // Unmarshal implements the gogo proto custom type interface. -func (d *Dec) Unmarshal(data []byte) error { +func (d *LegacyDec) Unmarshal(data []byte) error { if len(data) == 0 { d = nil return nil @@ -842,19 +842,19 @@ func (d *Dec) Unmarshal(data []byte) error { } // Size implements the gogo proto custom type interface. -func (d *Dec) Size() int { +func (d *LegacyDec) Size() int { bz, _ := d.Marshal() return len(bz) } // Override Amino binary serialization by proxying to protobuf. -func (d Dec) MarshalAmino() ([]byte, error) { return d.Marshal() } -func (d *Dec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } +func (d LegacyDec) MarshalAmino() ([]byte, error) { return d.Marshal() } +func (d *LegacyDec) UnmarshalAmino(bz []byte) error { return d.Unmarshal(bz) } // helpers // test if two decimal arrays are equal -func DecsEqual(d1s, d2s []Dec) bool { +func LegacyDecsEqual(d1s, d2s []LegacyDec) bool { if len(d1s) != len(d2s) { return false } @@ -868,7 +868,7 @@ func DecsEqual(d1s, d2s []Dec) bool { } // minimum decimal between two -func MinDec(d1, d2 Dec) Dec { +func LegacyMinDec(d1, d2 LegacyDec) LegacyDec { if d1.LT(d2) { return d1 } @@ -876,7 +876,7 @@ func MinDec(d1, d2 Dec) Dec { } // maximum decimal between two -func MaxDec(d1, d2 Dec) Dec { +func LegacyMaxDec(d1, d2 LegacyDec) LegacyDec { if d1.LT(d2) { return d2 } @@ -884,11 +884,11 @@ func MaxDec(d1, d2 Dec) Dec { } // intended to be used with require/assert: require.True(DecEq(...)) -func DecEq(t *testing.T, exp, got Dec) (*testing.T, bool, string, string, string) { +func LegacyDecEq(t *testing.T, exp, got LegacyDec) (*testing.T, bool, string, string, string) { return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String() } -func DecApproxEq(t *testing.T, d1 Dec, d2 Dec, tol Dec) (*testing.T, bool, string, string, string) { +func LegacyDecApproxEq(t *testing.T, d1 LegacyDec, d2 LegacyDec, tol LegacyDec) (*testing.T, bool, string, string, string) { diff := d1.Sub(d2).Abs() return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String() } diff --git a/math/dec_internal_test.go b/math/dec_internal_test.go index 960540735a9f..248bd4bc45ac 100644 --- a/math/dec_internal_test.go +++ b/math/dec_internal_test.go @@ -23,7 +23,7 @@ func (s *decimalInternalTestSuite) TestPrecisionMultiplier() { } func (s *decimalInternalTestSuite) TestZeroDeserializationJSON() { - d := Dec{new(big.Int)} + d := LegacyDec{new(big.Int)} err := json.Unmarshal([]byte(`"0"`), &d) s.Require().Nil(err) err = json.Unmarshal([]byte(`"{}"`), &d) @@ -31,26 +31,26 @@ func (s *decimalInternalTestSuite) TestZeroDeserializationJSON() { } func (s *decimalInternalTestSuite) TestSerializationGocodecJSON() { - d := MustNewDecFromStr("0.333") + d := LegacyMustNewDecFromStr("0.333") bz, err := json.Marshal(d) s.Require().NoError(err) - d2 := Dec{new(big.Int)} + d2 := LegacyDec{new(big.Int)} err = json.Unmarshal(bz, &d2) s.Require().NoError(err) s.Require().True(d.Equal(d2), "original: %v, unmarshalled: %v", d, d2) } func (s *decimalInternalTestSuite) TestDecMarshalJSON() { - decimal := func(i int64) Dec { - d := NewDec(0) + decimal := func(i int64) LegacyDec { + d := LegacyNewDec(0) d.i = new(big.Int).SetInt64(i) return d } tests := []struct { name string - d Dec + d LegacyDec want string wantErr bool // if wantErr = false, will also attempt unmarshaling }{ @@ -58,10 +58,10 @@ func (s *decimalInternalTestSuite) TestDecMarshalJSON() { {"one", decimal(1), "\"0.000000000000000001\"", false}, {"ten", decimal(10), "\"0.000000000000000010\"", false}, {"12340", decimal(12340), "\"0.000000000000012340\"", false}, - {"zeroInt", NewDec(0), "\"0.000000000000000000\"", false}, - {"oneInt", NewDec(1), "\"1.000000000000000000\"", false}, - {"tenInt", NewDec(10), "\"10.000000000000000000\"", false}, - {"12340Int", NewDec(12340), "\"12340.000000000000000000\"", false}, + {"zeroInt", LegacyNewDec(0), "\"0.000000000000000000\"", false}, + {"oneInt", LegacyNewDec(1), "\"1.000000000000000000\"", false}, + {"tenInt", LegacyNewDec(10), "\"10.000000000000000000\"", false}, + {"12340Int", LegacyNewDec(12340), "\"12340.000000000000000000\"", false}, } for _, tt := range tests { tt := tt @@ -73,7 +73,7 @@ func (s *decimalInternalTestSuite) TestDecMarshalJSON() { } if !tt.wantErr { s.Require().Equal(tt.want, string(got), "incorrect marshalled value") - unmarshalledDec := NewDec(0) + unmarshalledDec := LegacyNewDec(0) err := unmarshalledDec.UnmarshalJSON(got) s.Require().NoError(err) s.Require().Equal(tt.d, unmarshalledDec, "incorrect unmarshalled value") diff --git a/math/dec_test.go b/math/dec_test.go index 024a05bec16a..d390d4520133 100644 --- a/math/dec_test.go +++ b/math/dec_test.go @@ -25,30 +25,30 @@ func TestDecimalTestSuite(t *testing.T) { func TestDecApproxEq(t *testing.T) { // d1 = 0.55, d2 = 0.6, tol = 0.1 - d1 := math.NewDecWithPrec(55, 2) - d2 := math.NewDecWithPrec(6, 1) - tol := math.NewDecWithPrec(1, 1) + d1 := math.LegacyNewDecWithPrec(55, 2) + d2 := math.LegacyNewDecWithPrec(6, 1) + tol := math.LegacyNewDecWithPrec(1, 1) - require.True(math.DecApproxEq(t, d1, d2, tol)) + require.True(math.LegacyDecApproxEq(t, d1, d2, tol)) // d1 = 0.55, d2 = 0.6, tol = 1E-5 - d1 = math.NewDecWithPrec(55, 2) - d2 = math.NewDecWithPrec(6, 1) - tol = math.NewDecWithPrec(1, 5) + d1 = math.LegacyNewDecWithPrec(55, 2) + d2 = math.LegacyNewDecWithPrec(6, 1) + tol = math.LegacyNewDecWithPrec(1, 5) - require.False(math.DecApproxEq(t, d1, d2, tol)) + require.False(math.LegacyDecApproxEq(t, d1, d2, tol)) // d1 = 0.6, d2 = 0.61, tol = 0.01 - d1 = math.NewDecWithPrec(6, 1) - d2 = math.NewDecWithPrec(61, 2) - tol = math.NewDecWithPrec(1, 2) + d1 = math.LegacyNewDecWithPrec(6, 1) + d2 = math.LegacyNewDecWithPrec(61, 2) + tol = math.LegacyNewDecWithPrec(1, 2) - require.True(math.DecApproxEq(t, d1, d2, tol)) + require.True(math.LegacyDecApproxEq(t, d1, d2, tol)) } // create a decimal from a decimal string (ex. "1234.5678") -func (s *decimalTestSuite) mustNewDecFromStr(str string) (d math.Dec) { - d, err := math.NewDecFromStr(str) +func (s *decimalTestSuite) mustNewDecFromStr(str string) (d math.LegacyDec) { + d, err := math.LegacyNewDecFromStr(str) s.Require().NoError(err) return d @@ -67,38 +67,38 @@ func (s *decimalTestSuite) TestNewDecFromStr() { tests := []struct { decimalStr string expErr bool - exp math.Dec + exp math.LegacyDec }{ - {"", true, math.Dec{}}, - {"0.-75", true, math.Dec{}}, - {"0", false, math.NewDec(0)}, - {"1", false, math.NewDec(1)}, - {"1.1", false, math.NewDecWithPrec(11, 1)}, - {"0.75", false, math.NewDecWithPrec(75, 2)}, - {"0.8", false, math.NewDecWithPrec(8, 1)}, - {"0.11111", false, math.NewDecWithPrec(11111, 5)}, - {"314460551102969.3144278234343371835", true, math.NewDec(3141203149163817869)}, + {"", true, math.LegacyDec{}}, + {"0.-75", true, math.LegacyDec{}}, + {"0", false, math.LegacyNewDec(0)}, + {"1", false, math.LegacyNewDec(1)}, + {"1.1", false, math.LegacyNewDecWithPrec(11, 1)}, + {"0.75", false, math.LegacyNewDecWithPrec(75, 2)}, + {"0.8", false, math.LegacyNewDecWithPrec(8, 1)}, + {"0.11111", false, math.LegacyNewDecWithPrec(11111, 5)}, + {"314460551102969.3144278234343371835", true, math.LegacyNewDec(3141203149163817869)}, { "314460551102969314427823434337.1835718092488231350", - true, math.NewDecFromBigIntWithPrec(largeBigInt, 4), + true, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4), }, { "314460551102969314427823434337.1835", - false, math.NewDecFromBigIntWithPrec(largeBigInt, 4), + false, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4), }, - {".", true, math.Dec{}}, - {".0", true, math.NewDec(0)}, - {"1.", true, math.NewDec(1)}, - {"foobar", true, math.Dec{}}, - {"0.foobar", true, math.Dec{}}, - {"0.foobar.", true, math.Dec{}}, - {"8888888888888888888888888888888888888888888888888888888888888888888844444440", false, math.NewDecFromBigInt(largerBigInt)}, - {"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535", false, math.NewDecFromBigIntWithPrec(largestBigInt, 18)}, - {"133499189745056880149688856635597007162669032647290798121690100488888732861291", true, math.Dec{}}, + {".", true, math.LegacyDec{}}, + {".0", true, math.LegacyNewDec(0)}, + {"1.", true, math.LegacyNewDec(1)}, + {"foobar", true, math.LegacyDec{}}, + {"0.foobar", true, math.LegacyDec{}}, + {"0.foobar.", true, math.LegacyDec{}}, + {"8888888888888888888888888888888888888888888888888888888888888888888844444440", false, math.LegacyNewDecFromBigInt(largerBigInt)}, + {"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535", false, math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18)}, + {"133499189745056880149688856635597007162669032647290798121690100488888732861291", true, math.LegacyDec{}}, } for tcIndex, tc := range tests { - res, err := math.NewDecFromStr(tc.decimalStr) + res, err := math.LegacyNewDecFromStr(tc.decimalStr) if tc.expErr { s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { @@ -107,12 +107,12 @@ func (s *decimalTestSuite) TestNewDecFromStr() { } // negative tc - res, err = math.NewDecFromStr("-" + tc.decimalStr) + res, err = math.LegacyNewDecFromStr("-" + tc.decimalStr) if tc.expErr { s.Require().NotNil(err, "error expected, decimalStr %v, tc %v", tc.decimalStr, tcIndex) } else { s.Require().Nil(err, "unexpected error, decimalStr %v, tc %v", tc.decimalStr, tcIndex) - exp := tc.exp.Mul(math.NewDec(-1)) + exp := tc.exp.Mul(math.LegacyNewDec(-1)) s.Require().True(res.Equal(exp), "equality was incorrect, res %v, exp %v, tc %v", res, exp, tcIndex) } } @@ -120,17 +120,17 @@ func (s *decimalTestSuite) TestNewDecFromStr() { func (s *decimalTestSuite) TestDecString() { tests := []struct { - d math.Dec + d math.LegacyDec want string }{ - {math.NewDec(0), "0.000000000000000000"}, - {math.NewDec(1), "1.000000000000000000"}, - {math.NewDec(10), "10.000000000000000000"}, - {math.NewDec(12340), "12340.000000000000000000"}, - {math.NewDecWithPrec(12340, 4), "1.234000000000000000"}, - {math.NewDecWithPrec(12340, 5), "0.123400000000000000"}, - {math.NewDecWithPrec(12340, 8), "0.000123400000000000"}, - {math.NewDecWithPrec(1009009009009009009, 17), "10.090090090090090090"}, + {math.LegacyNewDec(0), "0.000000000000000000"}, + {math.LegacyNewDec(1), "1.000000000000000000"}, + {math.LegacyNewDec(10), "10.000000000000000000"}, + {math.LegacyNewDec(12340), "12340.000000000000000000"}, + {math.LegacyNewDecWithPrec(12340, 4), "1.234000000000000000"}, + {math.LegacyNewDecWithPrec(12340, 5), "0.123400000000000000"}, + {math.LegacyNewDecWithPrec(12340, 8), "0.000123400000000000"}, + {math.LegacyNewDecWithPrec(1009009009009009009, 17), "10.090090090090090090"}, } for tcIndex, tc := range tests { s.Require().Equal(tc.want, tc.d.String(), "bad String(), index: %v", tcIndex) @@ -139,17 +139,17 @@ func (s *decimalTestSuite) TestDecString() { func (s *decimalTestSuite) TestDecFloat64() { tests := []struct { - d math.Dec + d math.LegacyDec want float64 }{ - {math.NewDec(0), 0.000000000000000000}, - {math.NewDec(1), 1.000000000000000000}, - {math.NewDec(10), 10.000000000000000000}, - {math.NewDec(12340), 12340.000000000000000000}, - {math.NewDecWithPrec(12340, 4), 1.234000000000000000}, - {math.NewDecWithPrec(12340, 5), 0.123400000000000000}, - {math.NewDecWithPrec(12340, 8), 0.000123400000000000}, - {math.NewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, + {math.LegacyNewDec(0), 0.000000000000000000}, + {math.LegacyNewDec(1), 1.000000000000000000}, + {math.LegacyNewDec(10), 10.000000000000000000}, + {math.LegacyNewDec(12340), 12340.000000000000000000}, + {math.LegacyNewDecWithPrec(12340, 4), 1.234000000000000000}, + {math.LegacyNewDecWithPrec(12340, 5), 0.123400000000000000}, + {math.LegacyNewDecWithPrec(12340, 8), 0.000123400000000000}, + {math.LegacyNewDecWithPrec(1009009009009009009, 17), 10.090090090090090090}, } for tcIndex, tc := range tests { value, err := tc.d.Float64() @@ -161,31 +161,31 @@ func (s *decimalTestSuite) TestDecFloat64() { func (s *decimalTestSuite) TestEqualities() { tests := []struct { - d1, d2 math.Dec + d1, d2 math.LegacyDec gt, lt, eq bool }{ - {math.NewDec(0), math.NewDec(0), false, false, true}, - {math.NewDecWithPrec(0, 2), math.NewDecWithPrec(0, 4), false, false, true}, - {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(100, 0), false, false, true}, - {math.NewDecWithPrec(-100, 0), math.NewDecWithPrec(-100, 0), false, false, true}, - {math.NewDecWithPrec(-1, 1), math.NewDecWithPrec(-1, 1), false, false, true}, - {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(3333, 3), false, false, true}, - - {math.NewDecWithPrec(0, 0), math.NewDecWithPrec(3333, 3), false, true, false}, - {math.NewDecWithPrec(0, 0), math.NewDecWithPrec(100, 0), false, true, false}, - {math.NewDecWithPrec(-1, 0), math.NewDecWithPrec(3333, 3), false, true, false}, - {math.NewDecWithPrec(-1, 0), math.NewDecWithPrec(100, 0), false, true, false}, - {math.NewDecWithPrec(1111, 3), math.NewDecWithPrec(100, 0), false, true, false}, - {math.NewDecWithPrec(1111, 3), math.NewDecWithPrec(3333, 3), false, true, false}, - {math.NewDecWithPrec(-3333, 3), math.NewDecWithPrec(-1111, 3), false, true, false}, - - {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(0, 0), true, false, false}, - {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(0, 0), true, false, false}, - {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(-1, 0), true, false, false}, - {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(-1, 0), true, false, false}, - {math.NewDecWithPrec(100, 0), math.NewDecWithPrec(1111, 3), true, false, false}, - {math.NewDecWithPrec(3333, 3), math.NewDecWithPrec(1111, 3), true, false, false}, - {math.NewDecWithPrec(-1111, 3), math.NewDecWithPrec(-3333, 3), true, false, false}, + {math.LegacyNewDec(0), math.LegacyNewDec(0), false, false, true}, + {math.LegacyNewDecWithPrec(0, 2), math.LegacyNewDecWithPrec(0, 4), false, false, true}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(100, 0), false, false, true}, + {math.LegacyNewDecWithPrec(-100, 0), math.LegacyNewDecWithPrec(-100, 0), false, false, true}, + {math.LegacyNewDecWithPrec(-1, 1), math.LegacyNewDecWithPrec(-1, 1), false, false, true}, + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(3333, 3), false, false, true}, + + {math.LegacyNewDecWithPrec(0, 0), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, + {math.LegacyNewDecWithPrec(0, 0), math.LegacyNewDecWithPrec(100, 0), false, true, false}, + {math.LegacyNewDecWithPrec(-1, 0), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, + {math.LegacyNewDecWithPrec(-1, 0), math.LegacyNewDecWithPrec(100, 0), false, true, false}, + {math.LegacyNewDecWithPrec(1111, 3), math.LegacyNewDecWithPrec(100, 0), false, true, false}, + {math.LegacyNewDecWithPrec(1111, 3), math.LegacyNewDecWithPrec(3333, 3), false, true, false}, + {math.LegacyNewDecWithPrec(-3333, 3), math.LegacyNewDecWithPrec(-1111, 3), false, true, false}, + + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(0, 0), true, false, false}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(0, 0), true, false, false}, + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(-1, 0), true, false, false}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(-1, 0), true, false, false}, + {math.LegacyNewDecWithPrec(100, 0), math.LegacyNewDecWithPrec(1111, 3), true, false, false}, + {math.LegacyNewDecWithPrec(3333, 3), math.LegacyNewDecWithPrec(1111, 3), true, false, false}, + {math.LegacyNewDecWithPrec(-1111, 3), math.LegacyNewDecWithPrec(-3333, 3), true, false, false}, } for tcIndex, tc := range tests { @@ -197,65 +197,65 @@ func (s *decimalTestSuite) TestEqualities() { func (s *decimalTestSuite) TestDecsEqual() { tests := []struct { - d1s, d2s []math.Dec + d1s, d2s []math.LegacyDec eq bool }{ - {[]math.Dec{math.NewDec(0)}, []math.Dec{math.NewDec(0)}, true}, - {[]math.Dec{math.NewDec(0)}, []math.Dec{math.NewDec(1)}, false}, - {[]math.Dec{math.NewDec(0)}, []math.Dec{}, false}, - {[]math.Dec{math.NewDec(0), math.NewDec(1)}, []math.Dec{math.NewDec(0), math.NewDec(1)}, true}, - {[]math.Dec{math.NewDec(1), math.NewDec(0)}, []math.Dec{math.NewDec(1), math.NewDec(0)}, true}, - {[]math.Dec{math.NewDec(1), math.NewDec(0)}, []math.Dec{math.NewDec(0), math.NewDec(1)}, false}, - {[]math.Dec{math.NewDec(1), math.NewDec(0)}, []math.Dec{math.NewDec(1)}, false}, - {[]math.Dec{math.NewDec(1), math.NewDec(2)}, []math.Dec{math.NewDec(2), math.NewDec(4)}, false}, - {[]math.Dec{math.NewDec(3), math.NewDec(18)}, []math.Dec{math.NewDec(1), math.NewDec(6)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(0)}, true}, + {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(0)}, []math.LegacyDec{}, false}, + {[]math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, []math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, true}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, true}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(0), math.LegacyNewDec(1)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(0)}, []math.LegacyDec{math.LegacyNewDec(1)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(2)}, []math.LegacyDec{math.LegacyNewDec(2), math.LegacyNewDec(4)}, false}, + {[]math.LegacyDec{math.LegacyNewDec(3), math.LegacyNewDec(18)}, []math.LegacyDec{math.LegacyNewDec(1), math.LegacyNewDec(6)}, false}, } for tcIndex, tc := range tests { - s.Require().Equal(tc.eq, math.DecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) - s.Require().Equal(tc.eq, math.DecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) + s.Require().Equal(tc.eq, math.LegacyDecsEqual(tc.d1s, tc.d2s), "equality of decional arrays is incorrect, tc %d", tcIndex) + s.Require().Equal(tc.eq, math.LegacyDecsEqual(tc.d2s, tc.d1s), "equality of decional arrays is incorrect (converse), tc %d", tcIndex) } } func (s *decimalTestSuite) TestArithmetic() { tests := []struct { - d1, d2 math.Dec - expMul, expMulTruncate math.Dec - expQuo, expQuoRoundUp, expQuoTruncate math.Dec - expAdd, expSub math.Dec + d1, d2 math.LegacyDec + expMul, expMulTruncate math.LegacyDec + expQuo, expQuoRoundUp, expQuoTruncate math.LegacyDec + expAdd, expSub math.LegacyDec }{ // d1 d2 MUL MulTruncate QUO QUORoundUp QUOTrunctate ADD SUB - {math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0)}, - {math.NewDec(1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(1), math.NewDec(1)}, - {math.NewDec(0), math.NewDec(1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(1), math.NewDec(-1)}, - {math.NewDec(0), math.NewDec(-1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(-1), math.NewDec(1)}, - {math.NewDec(-1), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(0), math.NewDec(-1), math.NewDec(-1)}, + {math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0)}, + {math.LegacyNewDec(1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(1)}, + {math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(1), math.LegacyNewDec(-1)}, + {math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(1)}, + {math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(0), math.LegacyNewDec(-1), math.LegacyNewDec(-1)}, - {math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(2), math.NewDec(0)}, - {math.NewDec(-1), math.NewDec(-1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(-2), math.NewDec(0)}, - {math.NewDec(1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(0), math.NewDec(2)}, - {math.NewDec(-1), math.NewDec(1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(-1), math.NewDec(0), math.NewDec(-2)}, + {math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(2), math.LegacyNewDec(0)}, + {math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(-2), math.LegacyNewDec(0)}, + {math.LegacyNewDec(1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(2)}, + {math.LegacyNewDec(-1), math.LegacyNewDec(1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(-1), math.LegacyNewDec(0), math.LegacyNewDec(-2)}, { - math.NewDec(3), math.NewDec(7), math.NewDec(21), math.NewDec(21), - math.NewDecWithPrec(428571428571428571, 18), math.NewDecWithPrec(428571428571428572, 18), math.NewDecWithPrec(428571428571428571, 18), - math.NewDec(10), math.NewDec(-4), + math.LegacyNewDec(3), math.LegacyNewDec(7), math.LegacyNewDec(21), math.LegacyNewDec(21), + math.LegacyNewDecWithPrec(428571428571428571, 18), math.LegacyNewDecWithPrec(428571428571428572, 18), math.LegacyNewDecWithPrec(428571428571428571, 18), + math.LegacyNewDec(10), math.LegacyNewDec(-4), }, { - math.NewDec(2), math.NewDec(4), math.NewDec(8), math.NewDec(8), math.NewDecWithPrec(5, 1), math.NewDecWithPrec(5, 1), math.NewDecWithPrec(5, 1), - math.NewDec(6), math.NewDec(-2), + math.LegacyNewDec(2), math.LegacyNewDec(4), math.LegacyNewDec(8), math.LegacyNewDec(8), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), math.LegacyNewDecWithPrec(5, 1), + math.LegacyNewDec(6), math.LegacyNewDec(-2), }, - {math.NewDec(100), math.NewDec(100), math.NewDec(10000), math.NewDec(10000), math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(200), math.NewDec(0)}, + {math.LegacyNewDec(100), math.LegacyNewDec(100), math.LegacyNewDec(10000), math.LegacyNewDec(10000), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(200), math.LegacyNewDec(0)}, { - math.NewDecWithPrec(15, 1), math.NewDecWithPrec(15, 1), math.NewDecWithPrec(225, 2), math.NewDecWithPrec(225, 2), - math.NewDec(1), math.NewDec(1), math.NewDec(1), math.NewDec(3), math.NewDec(0), + math.LegacyNewDecWithPrec(15, 1), math.LegacyNewDecWithPrec(15, 1), math.LegacyNewDecWithPrec(225, 2), math.LegacyNewDecWithPrec(225, 2), + math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(1), math.LegacyNewDec(3), math.LegacyNewDec(0), }, { - math.NewDecWithPrec(3333, 4), math.NewDecWithPrec(333, 4), math.NewDecWithPrec(1109889, 8), math.NewDecWithPrec(1109889, 8), - math.MustNewDecFromStr("10.009009009009009009"), math.MustNewDecFromStr("10.009009009009009010"), math.MustNewDecFromStr("10.009009009009009009"), - math.NewDecWithPrec(3666, 4), math.NewDecWithPrec(3, 1), + math.LegacyNewDecWithPrec(3333, 4), math.LegacyNewDecWithPrec(333, 4), math.LegacyNewDecWithPrec(1109889, 8), math.LegacyNewDecWithPrec(1109889, 8), + math.LegacyMustNewDecFromStr("10.009009009009009009"), math.LegacyMustNewDecFromStr("10.009009009009009010"), math.LegacyMustNewDecFromStr("10.009009009009009009"), + math.LegacyNewDecWithPrec(3666, 4), math.LegacyNewDecWithPrec(3, 1), }, } @@ -289,7 +289,7 @@ func (s *decimalTestSuite) TestArithmetic() { func (s *decimalTestSuite) TestBankerRoundChop() { tests := []struct { - d1 math.Dec + d1 math.LegacyDec exp int64 }{ {s.mustNewDecFromStr("0.25"), 0}, @@ -315,7 +315,7 @@ func (s *decimalTestSuite) TestBankerRoundChop() { func (s *decimalTestSuite) TestTruncate() { tests := []struct { - d1 math.Dec + d1 math.LegacyDec exp int64 }{ {s.mustNewDecFromStr("0"), 0}, @@ -341,9 +341,9 @@ func (s *decimalTestSuite) TestTruncate() { func (s *decimalTestSuite) TestStringOverflow() { // two random 64 bit primes - dec1, err := math.NewDecFromStr("51643150036226787134389711697696177267") + dec1, err := math.LegacyNewDecFromStr("51643150036226787134389711697696177267") s.Require().NoError(err) - dec2, err := math.NewDecFromStr("-31798496660535729618459429845579852627") + dec2, err := math.LegacyNewDecFromStr("-31798496660535729618459429845579852627") s.Require().NoError(err) dec3 := dec1.Add(dec2) s.Require().Equal( @@ -354,14 +354,14 @@ func (s *decimalTestSuite) TestStringOverflow() { func (s *decimalTestSuite) TestDecMulInt() { tests := []struct { - sdkDec math.Dec + sdkDec math.LegacyDec sdkInt math.Int - want math.Dec + want math.LegacyDec }{ - {math.NewDec(10), math.NewInt(2), math.NewDec(20)}, - {math.NewDec(1000000), math.NewInt(100), math.NewDec(100000000)}, - {math.NewDecWithPrec(1, 1), math.NewInt(10), math.NewDec(1)}, - {math.NewDecWithPrec(1, 5), math.NewInt(20), math.NewDecWithPrec(2, 4)}, + {math.LegacyNewDec(10), math.NewInt(2), math.LegacyNewDec(20)}, + {math.LegacyNewDec(1000000), math.NewInt(100), math.LegacyNewDec(100000000)}, + {math.LegacyNewDecWithPrec(1, 1), math.NewInt(10), math.LegacyNewDec(1)}, + {math.LegacyNewDecWithPrec(1, 5), math.NewInt(20), math.LegacyNewDecWithPrec(2, 4)}, } for i, tc := range tests { got := tc.sdkDec.MulInt(tc.sdkInt) @@ -371,17 +371,17 @@ func (s *decimalTestSuite) TestDecMulInt() { func (s *decimalTestSuite) TestDecCeil() { testCases := []struct { - input math.Dec - expected math.Dec + input math.LegacyDec + expected math.LegacyDec }{ - {math.NewDecWithPrec(1000000000000000, math.Precision), math.NewDec(1)}, // 0.001 => 1.0 - {math.NewDecWithPrec(-1000000000000000, math.Precision), math.ZeroDec()}, // -0.001 => 0.0 - {math.ZeroDec(), math.ZeroDec()}, // 0.0 => 0.0 - {math.NewDecWithPrec(900000000000000000, math.Precision), math.NewDec(1)}, // 0.9 => 1.0 - {math.NewDecWithPrec(4001000000000000000, math.Precision), math.NewDec(5)}, // 4.001 => 5.0 - {math.NewDecWithPrec(-4001000000000000000, math.Precision), math.NewDec(-4)}, // -4.001 => -4.0 - {math.NewDecWithPrec(4700000000000000000, math.Precision), math.NewDec(5)}, // 4.7 => 5.0 - {math.NewDecWithPrec(-4700000000000000000, math.Precision), math.NewDec(-4)}, // -4.7 => -4.0 + {math.LegacyNewDecWithPrec(1000000000000000, math.LegacyPrecision), math.LegacyNewDec(1)}, // 0.001 => 1.0 + {math.LegacyNewDecWithPrec(-1000000000000000, math.LegacyPrecision), math.LegacyZeroDec()}, // -0.001 => 0.0 + {math.LegacyZeroDec(), math.LegacyZeroDec()}, // 0.0 => 0.0 + {math.LegacyNewDecWithPrec(900000000000000000, math.LegacyPrecision), math.LegacyNewDec(1)}, // 0.9 => 1.0 + {math.LegacyNewDecWithPrec(4001000000000000000, math.LegacyPrecision), math.LegacyNewDec(5)}, // 4.001 => 5.0 + {math.LegacyNewDecWithPrec(-4001000000000000000, math.LegacyPrecision), math.LegacyNewDec(-4)}, // -4.001 => -4.0 + {math.LegacyNewDecWithPrec(4700000000000000000, math.LegacyPrecision), math.LegacyNewDec(5)}, // 4.7 => 5.0 + {math.LegacyNewDecWithPrec(-4700000000000000000, math.LegacyPrecision), math.LegacyNewDec(-4)}, // -4.7 => -4.0 } for i, tc := range testCases { @@ -392,26 +392,26 @@ func (s *decimalTestSuite) TestDecCeil() { func (s *decimalTestSuite) TestPower() { testCases := []struct { - input math.Dec + input math.LegacyDec power uint64 - expected math.Dec + expected math.LegacyDec }{ - {math.NewDec(100), 0, math.OneDec()}, // 10 ^ (0) => 1.0 - {math.OneDec(), 10, math.OneDec()}, // 1.0 ^ (10) => 1.0 - {math.NewDecWithPrec(5, 1), 2, math.NewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 - {math.NewDecWithPrec(2, 1), 2, math.NewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 - {math.NewDecFromInt(math.NewInt(3)), 3, math.NewDecFromInt(math.NewInt(27))}, // 3 ^ 3 => 27 - {math.NewDecFromInt(math.NewInt(-3)), 4, math.NewDecFromInt(math.NewInt(81))}, // -3 ^ 4 = 81 - {math.NewDecWithPrec(1414213562373095049, 18), 2, math.NewDecFromInt(math.NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 + {math.LegacyNewDec(100), 0, math.LegacyOneDec()}, // 10 ^ (0) => 1.0 + {math.LegacyOneDec(), 10, math.LegacyOneDec()}, // 1.0 ^ (10) => 1.0 + {math.LegacyNewDecWithPrec(5, 1), 2, math.LegacyNewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 + {math.LegacyNewDecWithPrec(2, 1), 2, math.LegacyNewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 + {math.LegacyNewDecFromInt(math.NewInt(3)), 3, math.LegacyNewDecFromInt(math.NewInt(27))}, // 3 ^ 3 => 27 + {math.LegacyNewDecFromInt(math.NewInt(-3)), 4, math.LegacyNewDecFromInt(math.NewInt(81))}, // -3 ^ 4 = 81 + {math.LegacyNewDecWithPrec(1414213562373095049, 18), 2, math.LegacyNewDecFromInt(math.NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 } for i, tc := range testCases { res := tc.input.Power(tc.power) - s.Require().True(tc.expected.Sub(res).Abs().LTE(math.SmallestDec()), "unexpected result for test case %d, normal power, input: %v", i, tc.input) + s.Require().True(tc.expected.Sub(res).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, normal power, input: %v", i, tc.input) mutableInput := tc.input mutableInput.PowerMut(tc.power) - s.Require().True(tc.expected.Sub(mutableInput).Abs().LTE(math.SmallestDec()), + s.Require().True(tc.expected.Sub(mutableInput).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, input %v", i, tc.input) s.Require().True(res.Equal(tc.input), "unexpected result for test case %d, mutable power, input: %v", i, tc.input) } @@ -419,21 +419,21 @@ func (s *decimalTestSuite) TestPower() { func (s *decimalTestSuite) TestApproxRoot() { testCases := []struct { - input math.Dec + input math.LegacyDec root uint64 - expected math.Dec + expected math.LegacyDec }{ - {math.OneDec(), 10, math.OneDec()}, // 1.0 ^ (0.1) => 1.0 - {math.NewDecWithPrec(25, 2), 2, math.NewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 - {math.NewDecWithPrec(4, 2), 2, math.NewDecWithPrec(2, 1)}, // 0.04 ^ (0.5) => 0.2 - {math.NewDecFromInt(math.NewInt(27)), 3, math.NewDecFromInt(math.NewInt(3))}, // 27 ^ (1/3) => 3 - {math.NewDecFromInt(math.NewInt(-81)), 4, math.NewDecFromInt(math.NewInt(-3))}, // -81 ^ (0.25) => -3 - {math.NewDecFromInt(math.NewInt(2)), 2, math.NewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 - {math.NewDecWithPrec(1005, 3), 31536000, math.MustNewDecFromStr("1.000000000158153904")}, // 1.005 ^ (1/31536000) ≈ 1.00000000016 - {math.SmallestDec(), 2, math.NewDecWithPrec(1, 9)}, // 1e-18 ^ (0.5) => 1e-9 - {math.SmallestDec(), 3, math.MustNewDecFromStr("0.000000999999999997")}, // 1e-18 ^ (1/3) => 1e-6 - {math.NewDecWithPrec(1, 8), 3, math.MustNewDecFromStr("0.002154434690031900")}, // 1e-8 ^ (1/3) ≈ 0.00215443469 - {math.MustNewDecFromStr("9000002314687921634000000000000000000021394871242000000000000000"), 2, math.MustNewDecFromStr("94868342004527103646332858502867.899477053226766107")}, + {math.LegacyOneDec(), 10, math.LegacyOneDec()}, // 1.0 ^ (0.1) => 1.0 + {math.LegacyNewDecWithPrec(25, 2), 2, math.LegacyNewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 + {math.LegacyNewDecWithPrec(4, 2), 2, math.LegacyNewDecWithPrec(2, 1)}, // 0.04 ^ (0.5) => 0.2 + {math.LegacyNewDecFromInt(math.NewInt(27)), 3, math.LegacyNewDecFromInt(math.NewInt(3))}, // 27 ^ (1/3) => 3 + {math.LegacyNewDecFromInt(math.NewInt(-81)), 4, math.LegacyNewDecFromInt(math.NewInt(-3))}, // -81 ^ (0.25) => -3 + {math.LegacyNewDecFromInt(math.NewInt(2)), 2, math.LegacyNewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 + {math.LegacyNewDecWithPrec(1005, 3), 31536000, math.LegacyMustNewDecFromStr("1.000000000158153904")}, // 1.005 ^ (1/31536000) ≈ 1.00000000016 + {math.LegacySmallestDec(), 2, math.LegacyNewDecWithPrec(1, 9)}, // 1e-18 ^ (0.5) => 1e-9 + {math.LegacySmallestDec(), 3, math.LegacyMustNewDecFromStr("0.000000999999999997")}, // 1e-18 ^ (1/3) => 1e-6 + {math.LegacyNewDecWithPrec(1, 8), 3, math.LegacyMustNewDecFromStr("0.002154434690031900")}, // 1e-8 ^ (1/3) ≈ 0.00215443469 + {math.LegacyMustNewDecFromStr("9000002314687921634000000000000000000021394871242000000000000000"), 2, math.LegacyMustNewDecFromStr("94868342004527103646332858502867.899477053226766107")}, } // In the case of 1e-8 ^ (1/3), the result repeats every 5 iterations starting from iteration 24 @@ -443,21 +443,21 @@ func (s *decimalTestSuite) TestApproxRoot() { for i, tc := range testCases { res, err := tc.input.ApproxRoot(tc.root) s.Require().NoError(err) - s.Require().True(tc.expected.Sub(res).Abs().LTE(math.SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + s.Require().True(tc.expected.Sub(res).Abs().LTE(math.LegacySmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) } } func (s *decimalTestSuite) TestApproxSqrt() { testCases := []struct { - input math.Dec - expected math.Dec + input math.LegacyDec + expected math.LegacyDec }{ - {math.OneDec(), math.OneDec()}, // 1.0 => 1.0 - {math.NewDecWithPrec(25, 2), math.NewDecWithPrec(5, 1)}, // 0.25 => 0.5 - {math.NewDecWithPrec(4, 2), math.NewDecWithPrec(2, 1)}, // 0.09 => 0.3 - {math.NewDecFromInt(math.NewInt(9)), math.NewDecFromInt(math.NewInt(3))}, // 9 => 3 - {math.NewDecFromInt(math.NewInt(-9)), math.NewDecFromInt(math.NewInt(-3))}, // -9 => -3 - {math.NewDecFromInt(math.NewInt(2)), math.NewDecWithPrec(1414213562373095049, 18)}, // 2 => 1.414213562373095049 + {math.LegacyOneDec(), math.LegacyOneDec()}, // 1.0 => 1.0 + {math.LegacyNewDecWithPrec(25, 2), math.LegacyNewDecWithPrec(5, 1)}, // 0.25 => 0.5 + {math.LegacyNewDecWithPrec(4, 2), math.LegacyNewDecWithPrec(2, 1)}, // 0.09 => 0.3 + {math.LegacyNewDecFromInt(math.NewInt(9)), math.LegacyNewDecFromInt(math.NewInt(3))}, // 9 => 3 + {math.LegacyNewDecFromInt(math.NewInt(-9)), math.LegacyNewDecFromInt(math.NewInt(-3))}, // -9 => -3 + {math.LegacyNewDecFromInt(math.NewInt(2)), math.LegacyNewDecWithPrec(1414213562373095049, 18)}, // 2 => 1.414213562373095049 } for i, tc := range testCases { @@ -469,27 +469,27 @@ func (s *decimalTestSuite) TestApproxSqrt() { func (s *decimalTestSuite) TestDecSortableBytes() { tests := []struct { - d math.Dec + d math.LegacyDec want []byte }{ - {math.NewDec(0), []byte("000000000000000000.000000000000000000")}, - {math.NewDec(1), []byte("000000000000000001.000000000000000000")}, - {math.NewDec(10), []byte("000000000000000010.000000000000000000")}, - {math.NewDec(12340), []byte("000000000000012340.000000000000000000")}, - {math.NewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, - {math.NewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, - {math.NewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, - {math.NewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, - {math.NewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, - {math.NewDec(1000000000000000000), []byte("max")}, - {math.NewDec(-1000000000000000000), []byte("--")}, + {math.LegacyNewDec(0), []byte("000000000000000000.000000000000000000")}, + {math.LegacyNewDec(1), []byte("000000000000000001.000000000000000000")}, + {math.LegacyNewDec(10), []byte("000000000000000010.000000000000000000")}, + {math.LegacyNewDec(12340), []byte("000000000000012340.000000000000000000")}, + {math.LegacyNewDecWithPrec(12340, 4), []byte("000000000000000001.234000000000000000")}, + {math.LegacyNewDecWithPrec(12340, 5), []byte("000000000000000000.123400000000000000")}, + {math.LegacyNewDecWithPrec(12340, 8), []byte("000000000000000000.000123400000000000")}, + {math.LegacyNewDecWithPrec(1009009009009009009, 17), []byte("000000000000000010.090090090090090090")}, + {math.LegacyNewDecWithPrec(-1009009009009009009, 17), []byte("-000000000000000010.090090090090090090")}, + {math.LegacyNewDec(1000000000000000000), []byte("max")}, + {math.LegacyNewDec(-1000000000000000000), []byte("--")}, } for tcIndex, tc := range tests { - s.Require().Equal(tc.want, math.SortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) + s.Require().Equal(tc.want, math.LegacySortableDecBytes(tc.d), "bad String(), index: %v", tcIndex) } - s.Require().Panics(func() { math.SortableDecBytes(math.NewDec(1000000000000000001)) }) - s.Require().Panics(func() { math.SortableDecBytes(math.NewDec(-1000000000000000001)) }) + s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(1000000000000000001)) }) + s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(-1000000000000000001)) }) } func (s *decimalTestSuite) TestDecEncoding() { @@ -504,54 +504,54 @@ func (s *decimalTestSuite) TestDecEncoding() { s.Require().True(ok) testCases := []struct { - input math.Dec + input math.LegacyDec rawBz string jsonStr string yamlStr string }{ { - math.NewDec(0), "30", + math.LegacyNewDec(0), "30", "\"0.000000000000000000\"", "\"0.000000000000000000\"\n", }, { - math.NewDecWithPrec(4, 2), + math.LegacyNewDecWithPrec(4, 2), "3430303030303030303030303030303030", "\"0.040000000000000000\"", "\"0.040000000000000000\"\n", }, { - math.NewDecWithPrec(-4, 2), + math.LegacyNewDecWithPrec(-4, 2), "2D3430303030303030303030303030303030", "\"-0.040000000000000000\"", "\"-0.040000000000000000\"\n", }, { - math.NewDecWithPrec(1414213562373095049, 18), + math.LegacyNewDecWithPrec(1414213562373095049, 18), "31343134323133353632333733303935303439", "\"1.414213562373095049\"", "\"1.414213562373095049\"\n", }, { - math.NewDecWithPrec(-1414213562373095049, 18), + math.LegacyNewDecWithPrec(-1414213562373095049, 18), "2D31343134323133353632333733303935303439", "\"-1.414213562373095049\"", "\"-1.414213562373095049\"\n", }, { - math.NewDecFromBigIntWithPrec(largestBigInt, 18), + math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18), "3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", "\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", }, { - math.NewDecFromBigIntWithPrec(smallestBigInt, 18), + math.LegacyNewDecFromBigIntWithPrec(smallestBigInt, 18), "2D3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335", "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"", "\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n", }, { - math.NewDecFromBigIntWithPrec(maxInt, 18), + math.LegacyNewDecFromBigIntWithPrec(maxInt, 18), "3636373439353934383732353238343430303734383434343238333137373938353033353831333334353136333233363435333939303630383435303530323434343434333636343330363435303137313838323137353635323136373637", "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"", "\"66749594872528440074844428317798503581334516323645399060845050244444366430645.017188217565216767\"\n", @@ -563,7 +563,7 @@ func (s *decimalTestSuite) TestDecEncoding() { s.Require().NoError(err) s.Require().Equal(tc.rawBz, fmt.Sprintf("%X", bz)) - var other math.Dec + var other math.LegacyDec s.Require().NoError((&other).Unmarshal(bz)) s.Require().True(tc.input.Equal(other)) @@ -581,26 +581,26 @@ func (s *decimalTestSuite) TestDecEncoding() { // Showcase that different orders of operations causes different results. func (s *decimalTestSuite) TestOperationOrders() { - n1 := math.NewDec(10) - n2 := math.NewDec(1000000010) - s.Require().Equal(n1.Mul(n2).Quo(n2), math.NewDec(10)) + n1 := math.LegacyNewDec(10) + n2 := math.LegacyNewDec(1000000010) + s.Require().Equal(n1.Mul(n2).Quo(n2), math.LegacyNewDec(10)) s.Require().NotEqual(n1.Mul(n2).Quo(n2), n1.Quo(n2).Mul(n2)) } func BenchmarkMarshalTo(b *testing.B) { b.ReportAllocs() bis := []struct { - in math.Dec + in math.LegacyDec want []byte }{ { - math.NewDec(1e8), []byte{ + math.LegacyNewDec(1e8), []byte{ 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, }, }, - {math.NewDec(0), []byte{0x30}}, + {math.LegacyNewDec(0), []byte{0x30}}, } data := make([]byte, 100) diff --git a/types/math.go b/types/math.go index 18cbda5695c6..cc816d9fb0a5 100644 --- a/types/math.go +++ b/types/math.go @@ -37,34 +37,34 @@ func (ip IntProto) String() string { } type ( - Dec = sdkmath.Dec + Dec = sdkmath.LegacyDec ) const ( - Precision = sdkmath.Precision - DecimalPrecisionBits = sdkmath.DecimalPrecisionBits + Precision = sdkmath.LegacyPrecision + DecimalPrecisionBits = sdkmath.LegacyDecimalPrecisionBits ) var ( - ZeroDec = sdkmath.ZeroDec - OneDec = sdkmath.OneDec - SmallestDec = sdkmath.SmallestDec - NewDec = sdkmath.NewDec - NewDecWithPrec = sdkmath.NewDecWithPrec - NewDecFromBigInt = sdkmath.NewDecFromBigInt - NewDecFromBigIntWithPrec = sdkmath.NewDecFromBigIntWithPrec - NewDecFromInt = sdkmath.NewDecFromInt - NewDecFromIntWithPrec = sdkmath.NewDecFromIntWithPrec - NewDecFromStr = sdkmath.NewDecFromStr - MustNewDecFromStr = sdkmath.MustNewDecFromStr - MaxSortableDec = sdkmath.MaxSortableDec - ValidSortableDec = sdkmath.ValidSortableDec - SortableDecBytes = sdkmath.SortableDecBytes - DecsEqual = sdkmath.DecsEqual - MinDec = sdkmath.MinDec - MaxDec = sdkmath.MaxDec - DecEq = sdkmath.DecEq - DecApproxEq = sdkmath.DecApproxEq + ZeroDec = sdkmath.LegacyZeroDec + OneDec = sdkmath.LegacyOneDec + SmallestDec = sdkmath.LegacySmallestDec + NewDec = sdkmath.LegacyNewDec + NewDecWithPrec = sdkmath.LegacyNewDecWithPrec + NewDecFromBigInt = sdkmath.LegacyNewDecFromBigInt + NewDecFromBigIntWithPrec = sdkmath.LegacyNewDecFromBigIntWithPrec + NewDecFromInt = sdkmath.LegacyNewDecFromInt + NewDecFromIntWithPrec = sdkmath.LegacyNewDecFromIntWithPrec + NewDecFromStr = sdkmath.LegacyNewDecFromStr + MustNewDecFromStr = sdkmath.LegacyMustNewDecFromStr + MaxSortableDec = sdkmath.LegacyMaxSortableDec + ValidSortableDec = sdkmath.LegacyValidSortableDec + SortableDecBytes = sdkmath.LegacySortableDecBytes + DecsEqual = sdkmath.LegacyDecsEqual + MinDec = sdkmath.LegacyMinDec + MaxDec = sdkmath.LegacyMaxDec + DecEq = sdkmath.LegacyDecEq + DecApproxEq = sdkmath.LegacyDecApproxEq ) var _ CustomProtobufType = (*Dec)(nil)