refactor: Move sdk.Dec to math package (#12634)
## Description --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/main/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/main/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable)
This commit is contained in:
parent
7aef065c2f
commit
eee23d9531
@ -47,6 +47,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
|
||||
|
||||
1
go.mod
1
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
|
||||
|
||||
|
||||
2
go.sum
2
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=
|
||||
|
||||
@ -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, call it `LegacyDec`.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package types
|
||||
package math
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -10,26 +10,24 @@ import (
|
||||
"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 {
|
||||
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
|
||||
|
||||
@ -38,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)
|
||||
@ -48,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))
|
||||
}
|
||||
}
|
||||
@ -65,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)),
|
||||
}
|
||||
}
|
||||
@ -141,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
|
||||
@ -154,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, ".")
|
||||
@ -164,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
|
||||
}
|
||||
@ -228,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 {
|
||||
@ -265,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 {
|
||||
@ -280,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)
|
||||
|
||||
@ -297,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)
|
||||
|
||||
@ -313,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")
|
||||
@ -326,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 {
|
||||
@ -340,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)
|
||||
@ -359,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)
|
||||
@ -378,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)
|
||||
@ -397,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
|
||||
}
|
||||
@ -422,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
|
||||
@ -438,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)
|
||||
@ -464,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 {
|
||||
@ -489,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()
|
||||
}
|
||||
@ -527,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
|
||||
@ -560,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 {
|
||||
@ -647,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")
|
||||
@ -656,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))
|
||||
}
|
||||
|
||||
@ -673,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")
|
||||
@ -682,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)
|
||||
@ -701,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
|
||||
@ -759,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
|
||||
}
|
||||
@ -767,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)
|
||||
}
|
||||
@ -779,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
|
||||
}
|
||||
@ -789,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)
|
||||
}
|
||||
@ -802,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)
|
||||
}
|
||||
@ -822,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
|
||||
@ -844,23 +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 (dp DecProto) String() string {
|
||||
return dp.Dec.String()
|
||||
}
|
||||
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
|
||||
}
|
||||
@ -874,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
|
||||
}
|
||||
@ -882,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
|
||||
}
|
||||
@ -890,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()
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package types
|
||||
package math
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
@ -22,34 +23,34 @@ func (s *decimalInternalTestSuite) TestPrecisionMultiplier() {
|
||||
}
|
||||
|
||||
func (s *decimalInternalTestSuite) TestZeroDeserializationJSON() {
|
||||
d := Dec{new(big.Int)}
|
||||
err := cdc.UnmarshalJSON([]byte(`"0"`), &d)
|
||||
d := LegacyDec{new(big.Int)}
|
||||
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")
|
||||
d := LegacyMustNewDecFromStr("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)
|
||||
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
|
||||
}{
|
||||
@ -57,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
|
||||
@ -72,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")
|
||||
621
math/dec_test.go
Normal file
621
math/dec_test.go
Normal file
@ -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.LegacyNewDecWithPrec(55, 2)
|
||||
d2 := math.LegacyNewDecWithPrec(6, 1)
|
||||
tol := math.LegacyNewDecWithPrec(1, 1)
|
||||
|
||||
require.True(math.LegacyDecApproxEq(t, d1, d2, tol))
|
||||
|
||||
// d1 = 0.55, d2 = 0.6, tol = 1E-5
|
||||
d1 = math.LegacyNewDecWithPrec(55, 2)
|
||||
d2 = math.LegacyNewDecWithPrec(6, 1)
|
||||
tol = math.LegacyNewDecWithPrec(1, 5)
|
||||
|
||||
require.False(math.LegacyDecApproxEq(t, d1, d2, tol))
|
||||
|
||||
// d1 = 0.6, d2 = 0.61, tol = 0.01
|
||||
d1 = math.LegacyNewDecWithPrec(6, 1)
|
||||
d2 = math.LegacyNewDecWithPrec(61, 2)
|
||||
tol = math.LegacyNewDecWithPrec(1, 2)
|
||||
|
||||
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.LegacyDec) {
|
||||
d, err := math.LegacyNewDecFromStr(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.LegacyDec
|
||||
}{
|
||||
{"", 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.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4),
|
||||
},
|
||||
{
|
||||
"314460551102969314427823434337.1835",
|
||||
false, math.LegacyNewDecFromBigIntWithPrec(largeBigInt, 4),
|
||||
},
|
||||
{".", 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.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)
|
||||
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.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.LegacyNewDec(-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.LegacyDec
|
||||
want string
|
||||
}{
|
||||
{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)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *decimalTestSuite) TestDecFloat64() {
|
||||
tests := []struct {
|
||||
d math.LegacyDec
|
||||
want float64
|
||||
}{
|
||||
{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()
|
||||
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.LegacyDec
|
||||
gt, lt, eq bool
|
||||
}{
|
||||
{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 {
|
||||
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.LegacyDec
|
||||
eq bool
|
||||
}{
|
||||
{[]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.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.LegacyDec
|
||||
expMul, expMulTruncate math.LegacyDec
|
||||
expQuo, expQuoRoundUp, expQuoTruncate math.LegacyDec
|
||||
expAdd, expSub math.LegacyDec
|
||||
}{
|
||||
// d1 d2 MUL MulTruncate QUO QUORoundUp QUOTrunctate ADD SUB
|
||||
{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.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.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.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.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.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.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),
|
||||
},
|
||||
}
|
||||
|
||||
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.LegacyDec
|
||||
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.LegacyDec
|
||||
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.LegacyNewDecFromStr("51643150036226787134389711697696177267")
|
||||
s.Require().NoError(err)
|
||||
dec2, err := math.LegacyNewDecFromStr("-31798496660535729618459429845579852627")
|
||||
s.Require().NoError(err)
|
||||
dec3 := dec1.Add(dec2)
|
||||
s.Require().Equal(
|
||||
"19844653375691057515930281852116324640.000000000000000000",
|
||||
dec3.String(),
|
||||
)
|
||||
}
|
||||
|
||||
func (s *decimalTestSuite) TestDecMulInt() {
|
||||
tests := []struct {
|
||||
sdkDec math.LegacyDec
|
||||
sdkInt math.Int
|
||||
want math.LegacyDec
|
||||
}{
|
||||
{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)
|
||||
s.Require().Equal(tc.want, got, "Incorrect result on test case %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *decimalTestSuite) TestDecCeil() {
|
||||
testCases := []struct {
|
||||
input math.LegacyDec
|
||||
expected math.LegacyDec
|
||||
}{
|
||||
{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 {
|
||||
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.LegacyDec
|
||||
power uint64
|
||||
expected math.LegacyDec
|
||||
}{
|
||||
{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.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.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)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *decimalTestSuite) TestApproxRoot() {
|
||||
testCases := []struct {
|
||||
input math.LegacyDec
|
||||
root uint64
|
||||
expected math.LegacyDec
|
||||
}{
|
||||
{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
|
||||
// (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.LegacySmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *decimalTestSuite) TestApproxSqrt() {
|
||||
testCases := []struct {
|
||||
input math.LegacyDec
|
||||
expected math.LegacyDec
|
||||
}{
|
||||
{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 {
|
||||
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.LegacyDec
|
||||
want []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.LegacySortableDecBytes(tc.d), "bad String(), index: %v", tcIndex)
|
||||
}
|
||||
|
||||
s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(1000000000000000001)) })
|
||||
s.Require().Panics(func() { math.LegacySortableDecBytes(math.LegacyNewDec(-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.LegacyDec
|
||||
rawBz string
|
||||
jsonStr string
|
||||
yamlStr string
|
||||
}{
|
||||
{
|
||||
math.LegacyNewDec(0), "30",
|
||||
"\"0.000000000000000000\"",
|
||||
"\"0.000000000000000000\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecWithPrec(4, 2),
|
||||
"3430303030303030303030303030303030",
|
||||
"\"0.040000000000000000\"",
|
||||
"\"0.040000000000000000\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecWithPrec(-4, 2),
|
||||
"2D3430303030303030303030303030303030",
|
||||
"\"-0.040000000000000000\"",
|
||||
"\"-0.040000000000000000\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecWithPrec(1414213562373095049, 18),
|
||||
"31343134323133353632333733303935303439",
|
||||
"\"1.414213562373095049\"",
|
||||
"\"1.414213562373095049\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecWithPrec(-1414213562373095049, 18),
|
||||
"2D31343134323133353632333733303935303439",
|
||||
"\"-1.414213562373095049\"",
|
||||
"\"-1.414213562373095049\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecFromBigIntWithPrec(largestBigInt, 18),
|
||||
"3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335",
|
||||
"\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"",
|
||||
"\"33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecFromBigIntWithPrec(smallestBigInt, 18),
|
||||
"2D3333343939313839373435303536383830313439363838383536363335353937303037313632363639303332363437323930373938313231363930313030343838383838373332383631323930303334333736343335313330343333353335",
|
||||
"\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"",
|
||||
"\"-33499189745056880149688856635597007162669032647290798121690100488888732861290.034376435130433535\"\n",
|
||||
},
|
||||
{
|
||||
math.LegacyNewDecFromBigIntWithPrec(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.LegacyDec
|
||||
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.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.LegacyDec
|
||||
want []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.LegacyNewDec(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
)
|
||||
|
||||
@ -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=
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,3 +35,40 @@ const (
|
||||
func (ip IntProto) String() string {
|
||||
return ip.Int.String()
|
||||
}
|
||||
|
||||
type (
|
||||
Dec = sdkmath.LegacyDec
|
||||
)
|
||||
|
||||
const (
|
||||
Precision = sdkmath.LegacyPrecision
|
||||
DecimalPrecisionBits = sdkmath.LegacyDecimalPrecisionBits
|
||||
)
|
||||
|
||||
var (
|
||||
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)
|
||||
|
||||
func (dp DecProto) String() string {
|
||||
return dp.Dec.String()
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user