Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(osmomath): BigDec Clone() and MulMut methods (backport #3678) #3679

Merged
merged 1 commit into from
Dec 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Misc Improvements

* [#2788](https://github.com/osmosis-labs/osmosis/pull/2788) Add logarithm base 2 implementation.
* [#3677](https://github.com/osmosis-labs/osmosis/pull/3677) Add methods for cloning and mutative multiplication on osmomath.BigDec.

### Features

### Bug fixes
Expand Down
27 changes: 22 additions & 5 deletions osmomath/decimal.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,32 @@ func (d BigDec) Sub(d2 BigDec) BigDec {
return BigDec{res}
}

// multiplication
// Clone performs a deep copy of the receiver
// and returns the new result.
func (d BigDec) Clone() BigDec {
copy := BigDec{new(big.Int)}
copy.i.Set(d.i)
return copy
}

// Mut performs non-mutative multiplication.
// The receiver is not modifier but the result is.
func (d BigDec) Mul(d2 BigDec) BigDec {
mul := new(big.Int).Mul(d.i, d2.i)
chopped := chopPrecisionAndRound(mul)
copy := d.Clone()
copy.MulMut(d2)
return copy
}

if chopped.BitLen() > maxDecBitLen {
// Mut performs non-mutative multiplication.
// The receiver is not modifier but the result is.
func (d BigDec) MulMut(d2 BigDec) BigDec {
d.i.Mul(d.i, d2.i)
d.i = chopPrecisionAndRound(d.i)

if d.i.BitLen() > maxDecBitLen {
panic("Int overflow")
}
return BigDec{chopped}
return BigDec{d.i}
}

// multiplication truncate
Expand Down
82 changes: 82 additions & 0 deletions osmomath/decimal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1030,3 +1030,85 @@ func (s *decimalTestSuite) TestCustomBaseLog() {
})
}
}

func (s *decimalTestSuite) TestClone() {

// The value to change the underlying copy's
// internal value to assert on the original BigDec
// remaining unchanged.
changeValue := big.NewInt(10)

tests := map[string]struct {
startValue BigDec
}{
"1.1": {
startValue: MustNewDecFromStr("1.1"),
},
"-3": {
startValue: MustNewDecFromStr("-3"),
},
"0": {
startValue: MustNewDecFromStr("-3"),
},
}

for name, tc := range tests {
tc := tc
s.Run(name, func() {

copy := tc.startValue.Clone()

s.Require().Equal(tc.startValue, copy)

copy.i.Set(changeValue)
// copy and startValue do not share internals.
s.Require().NotEqual(tc.startValue, copy)
})
}
}

// TestMul_Mutation tests that MulMut mutates the receiver
// while Mut is not.
func (s *decimalTestSuite) TestMul_Mutation() {

mulBy := MustNewDecFromStr("2")

tests := map[string]struct {
startValue BigDec
expectedMulResult BigDec
}{
"1.1": {
startValue: MustNewDecFromStr("1.1"),
expectedMulResult: MustNewDecFromStr("2.2"),
},
"-3": {
startValue: MustNewDecFromStr("-3"),
expectedMulResult: MustNewDecFromStr("-6"),
},
"0": {
startValue: ZeroDec(),
expectedMulResult: ZeroDec(),
},
}

for name, tc := range tests {
tc := tc
s.Run(name, func() {

startMut := tc.startValue.Clone()
startNonMut := tc.startValue.Clone()

resultMut := startMut.MulMut(mulBy)
result := startNonMut.Mul(mulBy)

// assert both results are as expectde.
s.Require().Equal(tc.expectedMulResult, resultMut)
s.Require().Equal(tc.expectedMulResult, result)

// assert MulMut mutated the receiver
s.Require().Equal(tc.expectedMulResult, startMut)
// assert Mul did not mutate the receiver
s.Require().Equal(tc.startValue, startNonMut)
})
}
}