From 54f6997418ea3a7bd74b744eabee25c9da4a5995 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Sat, 14 Dec 2019 17:46:06 -0800 Subject: [PATCH 01/12] in progress: --- types/decimal.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/types/decimal.go b/types/decimal.go index b066c3e43374..ca1898310005 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -318,6 +318,56 @@ func (d Dec) QuoInt64(i int64) Dec { return Dec{mul} } +// ApproxRoot returns an approximate sqrt estimation using Newton's method to +// compute square roots x=√d for d > 0. The algorithm starts with some guess and +// computes the sequence of improved guesses until an answer converges to an +// approximate answer. It returns -(sqrt(abs(d)) if input is negative. +func (d Dec) ApproxRoot(root Uint) Dec { + if d.IsNegative() { + return d.MulInt64(-1).ApproxRoot(root).MulInt64(-1) + } + + if d.IsZero() { + return ZeroDec() + } + + if root == 1 { + return d + } + + if root == 0 { + return OneDec() + } + + z := OneDec() + // first guess + z = z.Sub((z.Mul(z).Sub(d)).Quo(z.MulInt64(2))) + + // iterate until change is very small + for zNew, delta := z, z; delta.GT(SmallestDec()); z = zNew { + zNew = zNew.MulInt64(root - 1).Add(A.Quo(zNew.Power(root - 1))).Quo(root) + zNew = zNew.Sub((zNew.Mul(zNew).Sub(d)).Quo(zNew.MulInt64(2))) + delta = z.Sub(zNew) + } + + return z +} + +func (d Dec) Power(power Int) Dec { + if power == 0 { + return OneDec() + } + + tmp := d.Power(power.Quo(NewInt(2))) + if power.Quo(NewInt(2)).IsZero() { + return tmp.Mul(tmp) + } + if power.GT(ZeroInt()) { + return d.Mul(tmp.Mul(tmp)) + } + return tmp.Mul(tmp).Quo(d) +} + // ApproxSqrt returns an approximate sqrt estimation using Newton's method to // compute square roots x=√d for d > 0. The algorithm starts with some guess and // computes the sequence of improved guesses until an answer converges to an From b9c341ec493359f45d05ae826ded6e6838c68a30 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 24 Dec 2019 16:23:53 -0500 Subject: [PATCH 02/12] find nth root of sdk.Dec --- types/decimal.go | 83 +++++++++++++++++++------------------------ types/decimal_test.go | 40 +++++++++++++++++++++ types/int.go | 7 ++++ 3 files changed, 83 insertions(+), 47 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index ca1898310005..c59f244bfca3 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -318,17 +318,18 @@ func (d Dec) QuoInt64(i int64) Dec { return Dec{mul} } -// ApproxRoot returns an approximate sqrt estimation using Newton's method to -// compute square roots x=√d for d > 0. The algorithm starts with some guess and +// ApproxRoot returns an approximate estimation of a Dec's positive real nth root +// using Newton's method (where n is positive). The algorithm starts with some guess and // computes the sequence of improved guesses until an answer converges to an -// approximate answer. It returns -(sqrt(abs(d)) if input is negative. -func (d Dec) ApproxRoot(root Uint) Dec { +// approximate answer. It returns -(sqrt(abs(d)) if input is negative. +func (d Dec) ApproxRoot(root uint64) Dec { + if d.IsNegative() { return d.MulInt64(-1).ApproxRoot(root).MulInt64(-1) } - if d.IsZero() { - return ZeroDec() + if d.IsZero() || d.Equal(OneDec()) { + return d } if root == 1 { @@ -339,59 +340,47 @@ func (d Dec) ApproxRoot(root Uint) Dec { return OneDec() } - z := OneDec() - // first guess - z = z.Sub((z.Mul(z).Sub(d)).Quo(z.MulInt64(2))) + rootInt := NewIntFromUint64(root) + guess := d.QuoInt(rootInt) + delta := OneDec() + + fmt.Println(guess, delta) + + for delta.Abs().GT(SmallestDec()) { + prev := guess.Power(root - 1) + delta = d.Quo(prev) + delta = delta.Sub(guess) + delta = delta.QuoInt(rootInt) - // iterate until change is very small - for zNew, delta := z, z; delta.GT(SmallestDec()); z = zNew { - zNew = zNew.MulInt64(root - 1).Add(A.Quo(zNew.Power(root - 1))).Quo(root) - zNew = zNew.Sub((zNew.Mul(zNew).Sub(d)).Quo(zNew.MulInt64(2))) - delta = z.Sub(zNew) + guess = guess.Add(delta) + fmt.Println(guess, delta) } - return z + return guess } -func (d Dec) Power(power Int) Dec { +// Power returns a the result of raising to a positive integer power +func (d Dec) Power(power uint64) Dec { if power == 0 { return OneDec() } - - tmp := d.Power(power.Quo(NewInt(2))) - if power.Quo(NewInt(2)).IsZero() { - return tmp.Mul(tmp) - } - if power.GT(ZeroInt()) { - return d.Mul(tmp.Mul(tmp)) + tmp := OneDec() + for i := power; i > 1; { + if i%2 == 0 { + i /= 2 + } else { + tmp = tmp.Mul(d) + i = (i - 1) / 2 + } + d = d.Mul(d) } - return tmp.Mul(tmp).Quo(d) + return d.Mul(tmp) } -// ApproxSqrt returns an approximate sqrt estimation using Newton's method to -// compute square roots x=√d for d > 0. The algorithm starts with some guess and -// computes the sequence of improved guesses until an answer converges to an -// approximate answer. It returns -(sqrt(abs(d)) if input is negative. +// ApproxSqrt is a wrapper around ApproxRoot for the common special case +// of finding square root of a number. func (d Dec) ApproxSqrt() Dec { - if d.IsNegative() { - return d.MulInt64(-1).ApproxSqrt().MulInt64(-1) - } - - if d.IsZero() { - return ZeroDec() - } - - z := OneDec() - // first guess - z = z.Sub((z.Mul(z).Sub(d)).Quo(z.MulInt64(2))) - - // iterate until change is very small - for zNew, delta := z, z; delta.GT(SmallestDec()); z = zNew { - zNew = zNew.Sub((zNew.Mul(zNew).Sub(d)).Quo(zNew.MulInt64(2))) - delta = z.Sub(zNew) - } - - return z + return d.ApproxRoot(2) } // is integer, e.g. decimals are zero diff --git a/types/decimal_test.go b/types/decimal_test.go index ea97a1029a5a..97655d41cec5 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -425,6 +425,46 @@ func TestDecCeil(t *testing.T) { } } +func TestPower(t *testing.T) { + testCases := []struct { + input Dec + power uint64 + expected Dec + }{ + {OneDec(), 10, OneDec()}, // 1.0 ^ (10) => 1.0 + {NewDecWithPrec(5, 1), 2, NewDecWithPrec(25, 2)}, // 0.5 ^ 2 => 0.25 + {NewDecWithPrec(2, 1), 2, NewDecWithPrec(4, 2)}, // 0.2 ^ 2 => 0.04 + {NewDecFromInt(NewInt(3)), 3, NewDecFromInt(NewInt(27))}, // 3 ^ 3 => 27 + {NewDecFromInt(NewInt(-3)), 4, NewDecFromInt(NewInt(81))}, // -3 ^ 4 = 81 + {NewDecWithPrec(1414213562373095049, 18), 2, NewDecFromInt(NewInt(2))}, // 1.414213562373095049 ^ 2 = 2 + } + + for i, tc := range testCases { + res := tc.input.Power(tc.power) + require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + } +} + +func TestApproxRoot(t *testing.T) { + testCases := []struct { + input Dec + root uint64 + expected Dec + }{ + {OneDec(), 10, OneDec()}, // 1.0 ^ (0.1) => 1.0 + {NewDecWithPrec(25, 2), 2, NewDecWithPrec(5, 1)}, // 0.25 ^ (0.5) => 0.5 + {NewDecWithPrec(4, 2), 2, NewDecWithPrec(2, 1)}, // 0.04 => 0.2 + {NewDecFromInt(NewInt(27)), 3, NewDecFromInt(NewInt(3))}, // 27 ^ (1/3) => 3 + {NewDecFromInt(NewInt(-81)), 4, NewDecFromInt(NewInt(-3))}, // -81 ^ (0.25) => -3 + {NewDecFromInt(NewInt(2)), 2, NewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 + } + + for i, tc := range testCases { + res := tc.input.ApproxRoot(tc.root) + require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) + } +} + func TestApproxSqrt(t *testing.T) { testCases := []struct { input Dec diff --git a/types/int.go b/types/int.go index 41a6efef74c7..067b822c1066 100644 --- a/types/int.go +++ b/types/int.go @@ -114,6 +114,13 @@ func NewInt(n int64) Int { return Int{big.NewInt(n)} } +// NewInt constructs Int from int64 +func NewIntFromUint64(n uint64) Int { + b := big.NewInt(0) + b.SetUint64(n) + return Int{b} +} + // NewIntFromBigInt constructs Int from big.Int func NewIntFromBigInt(i *big.Int) Int { if i.BitLen() > maxBitLen { From 60c3482d8e665f7b884f1309d81d102c94cfbc4f Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 24 Dec 2019 16:27:03 -0500 Subject: [PATCH 03/12] remove print statements --- types/decimal.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index c59f244bfca3..cfd5723ed825 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -344,8 +344,6 @@ func (d Dec) ApproxRoot(root uint64) Dec { guess := d.QuoInt(rootInt) delta := OneDec() - fmt.Println(guess, delta) - for delta.Abs().GT(SmallestDec()) { prev := guess.Power(root - 1) delta = d.Quo(prev) @@ -353,7 +351,6 @@ func (d Dec) ApproxRoot(root uint64) Dec { delta = delta.QuoInt(rootInt) guess = guess.Add(delta) - fmt.Println(guess, delta) } return guess From 82b0ee95a081c24a97224bb05f8f3cf31b869c7a Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 24 Dec 2019 19:41:47 -0500 Subject: [PATCH 04/12] initial guess as 1 --- types/decimal.go | 8 +++++++- types/decimal_test.go | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/types/decimal.go b/types/decimal.go index cfd5723ed825..72a56955f413 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -341,16 +341,22 @@ func (d Dec) ApproxRoot(root uint64) Dec { } rootInt := NewIntFromUint64(root) - guess := d.QuoInt(rootInt) + guess := OneDec() delta := OneDec() + fmt.Println(guess, delta) + for delta.Abs().GT(SmallestDec()) { prev := guess.Power(root - 1) + if prev.IsZero() { + prev = SmallestDec() + } delta = d.Quo(prev) delta = delta.Sub(guess) delta = delta.QuoInt(rootInt) guess = guess.Add(delta) + fmt.Println(guess, delta) } return guess diff --git a/types/decimal_test.go b/types/decimal_test.go index 97655d41cec5..6e9e2bdcc3d0 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,6 +1,7 @@ package types import ( + "fmt" "math/big" "testing" @@ -457,9 +458,11 @@ func TestApproxRoot(t *testing.T) { {NewDecFromInt(NewInt(27)), 3, NewDecFromInt(NewInt(3))}, // 27 ^ (1/3) => 3 {NewDecFromInt(NewInt(-81)), 4, NewDecFromInt(NewInt(-3))}, // -81 ^ (0.25) => -3 {NewDecFromInt(NewInt(2)), 2, NewDecWithPrec(1414213562373095049, 18)}, // 2 ^ (0.5) => 1.414213562373095049 + {NewDecWithPrec(1005, 3), 31536000, MustNewDecFromStr("1.000000000158153904")}, } for i, tc := range testCases { + fmt.Println(i) res := tc.input.ApproxRoot(tc.root) require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) } From b0b39eced9782059f41fa6c6d12ff980644fd8b8 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Tue, 24 Dec 2019 20:00:40 -0500 Subject: [PATCH 05/12] added error handling --- types/decimal.go | 36 +++++++++++++++++++----------------- types/decimal_test.go | 6 ++++-- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 72a56955f413..4436ac9a3fa9 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "errors" "fmt" "math/big" "strconv" @@ -261,7 +262,6 @@ func (d Dec) MulInt64(i int64) Dec { // quotient func (d Dec) Quo(d2 Dec) Dec { - // multiply precision twice mul := new(big.Int).Mul(d.Int, precisionReuse) mul.Mul(mul, precisionReuse) @@ -322,29 +322,32 @@ func (d Dec) QuoInt64(i int64) Dec { // using Newton's method (where n is positive). The algorithm starts with some guess and // computes the sequence of improved guesses until an answer converges to an // approximate answer. It returns -(sqrt(abs(d)) if input is negative. -func (d Dec) ApproxRoot(root uint64) Dec { +func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + err, ok = r.(error) + if !ok { + err = errors.New("out of bounds") + } + } + }() if d.IsNegative() { - return d.MulInt64(-1).ApproxRoot(root).MulInt64(-1) - } - - if d.IsZero() || d.Equal(OneDec()) { - return d + absRoot, err := d.MulInt64(-1).ApproxRoot(root) + return absRoot.MulInt64(-1), err } - if root == 1 { - return d + if root == 1 || d.IsZero() || d.Equal(OneDec()) { + return d, nil } if root == 0 { - return OneDec() + return OneDec(), nil } rootInt := NewIntFromUint64(root) - guess := OneDec() - delta := OneDec() - - fmt.Println(guess, delta) + guess, delta := OneDec(), OneDec() for delta.Abs().GT(SmallestDec()) { prev := guess.Power(root - 1) @@ -356,10 +359,9 @@ func (d Dec) ApproxRoot(root uint64) Dec { delta = delta.QuoInt(rootInt) guess = guess.Add(delta) - fmt.Println(guess, delta) } - return guess + return guess, nil } // Power returns a the result of raising to a positive integer power @@ -382,7 +384,7 @@ func (d Dec) Power(power uint64) Dec { // ApproxSqrt is a wrapper around ApproxRoot for the common special case // of finding square root of a number. -func (d Dec) ApproxSqrt() Dec { +func (d Dec) ApproxSqrt() (Dec, error) { return d.ApproxRoot(2) } diff --git a/types/decimal_test.go b/types/decimal_test.go index 6e9e2bdcc3d0..6d8c2bb9ae5a 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -463,7 +463,8 @@ func TestApproxRoot(t *testing.T) { for i, tc := range testCases { fmt.Println(i) - res := tc.input.ApproxRoot(tc.root) + res, err := tc.input.ApproxRoot(tc.root) + require.Nil(t, err) require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) } } @@ -482,7 +483,8 @@ func TestApproxSqrt(t *testing.T) { } for i, tc := range testCases { - res := tc.input.ApproxSqrt() + res, err := tc.input.ApproxSqrt() + require.Nil(t, err) require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) } } From b59d9994d0ed8249c8db9eebd3be887120f50ab9 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Thu, 26 Dec 2019 18:37:02 -0500 Subject: [PATCH 06/12] Update types/decimal_test.go Co-Authored-By: Kevin Davis --- types/decimal_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/types/decimal_test.go b/types/decimal_test.go index 6d8c2bb9ae5a..efe7ad2b7128 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -462,7 +462,6 @@ func TestApproxRoot(t *testing.T) { } for i, tc := range testCases { - fmt.Println(i) res, err := tc.input.ApproxRoot(tc.root) require.Nil(t, err) require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) From fd6631af84dbced0c26106994e018aa8013de199 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Mon, 30 Dec 2019 13:03:31 -0800 Subject: [PATCH 07/12] Apply suggestions from code review Co-Authored-By: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- types/decimal.go | 4 ++-- types/decimal_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/types/decimal.go b/types/decimal.go index 4436ac9a3fa9..bd69cf3fb165 100644 --- a/types/decimal.go +++ b/types/decimal.go @@ -321,7 +321,7 @@ func (d Dec) QuoInt64(i int64) Dec { // ApproxRoot returns an approximate estimation of a Dec's positive real nth root // using Newton's method (where n is positive). The algorithm starts with some guess and // computes the sequence of improved guesses until an answer converges to an -// approximate answer. It returns -(sqrt(abs(d)) if input is negative. +// approximate answer. It returns `|d|.ApproxRoot() * -1` if input is negative. func (d Dec) ApproxRoot(root uint64) (guess Dec, err error) { defer func() { if r := recover(); r != nil { @@ -383,7 +383,7 @@ func (d Dec) Power(power uint64) Dec { } // ApproxSqrt is a wrapper around ApproxRoot for the common special case -// of finding square root of a number. +// of finding the square root of a number. It returns -(sqrt(abs(d)) if input is negative. func (d Dec) ApproxSqrt() (Dec, error) { return d.ApproxRoot(2) } diff --git a/types/decimal_test.go b/types/decimal_test.go index efe7ad2b7128..89a41e96b765 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -463,7 +463,7 @@ func TestApproxRoot(t *testing.T) { for i, tc := range testCases { res, err := tc.input.ApproxRoot(tc.root) - require.Nil(t, err) + require.NoError(t, err) require.True(t, tc.expected.Sub(res).Abs().LTE(SmallestDec()), "unexpected result for test case %d, input: %v", i, tc.input) } } @@ -483,7 +483,7 @@ func TestApproxSqrt(t *testing.T) { for i, tc := range testCases { res, err := tc.input.ApproxSqrt() - require.Nil(t, err) + require.NoError(t, err) require.Equal(t, tc.expected, res, "unexpected result for test case %d, input: %v", i, tc.input) } } From dce3a414b094ab8054b7b08c395746310bc069e6 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Mon, 30 Dec 2019 13:13:01 -0800 Subject: [PATCH 08/12] added uint test --- types/int.go | 14 ++++++++++++++ types/int_test.go | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/types/int.go b/types/int.go index 067b822c1066..cb2b1396dc48 100644 --- a/types/int.go +++ b/types/int.go @@ -185,6 +185,20 @@ func (i Int) IsInt64() bool { return i.i.IsInt64() } +// Uint64 converts Int to uint64 +// Panics if the value is out of range +func (i Int) Uint64() uint64 { + if !i.i.IsUint64() { + panic("Int64() out of bound") + } + return i.i.Uint64() +} + +// IsUint64 returns true if Uint64() not panics +func (i Int) IsUint64() bool { + return i.i.IsUint64() +} + // IsZero returns true if Int is zero func (i Int) IsZero() bool { return i.i.Sign() == 0 diff --git a/types/int_test.go b/types/int_test.go index f6dbc1b407e9..072b2f47bb9a 100644 --- a/types/int_test.go +++ b/types/int_test.go @@ -16,6 +16,14 @@ func TestFromInt64(t *testing.T) { } } +func TestFromUint64(t *testing.T) { + for n := 0; n < 20; n++ { + r := rand.Uint64() + require.True(t, NewIntFromUint64(r).IsUint64()) + require.Equal(t, r, NewIntFromUint64(r).Uint64()) + } +} + func TestIntPanic(t *testing.T) { // Max Int = 2^255-1 = 5.789e+76 // Min Int = -(2^255-1) = -5.789e+76 From e28947ed3c20883967035f03463cdeff7782f35b Mon Sep 17 00:00:00 2001 From: Federico Kunze <31522760+fedekunze@users.noreply.github.com> Date: Thu, 2 Jan 2020 10:05:47 -0300 Subject: [PATCH 09/12] Update types/int.go Co-Authored-By: Alexander Bezobchuk --- types/int.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/int.go b/types/int.go index cb2b1396dc48..67d106030818 100644 --- a/types/int.go +++ b/types/int.go @@ -189,7 +189,7 @@ func (i Int) IsInt64() bool { // Panics if the value is out of range func (i Int) Uint64() uint64 { if !i.i.IsUint64() { - panic("Int64() out of bound") + panic("Uint64() out of bounds") } return i.i.Uint64() } From eba88f120ac9e0bde753274d590304eee53b20c8 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Thu, 2 Jan 2020 13:08:23 -0500 Subject: [PATCH 10/12] fix golint --- types/decimal_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/types/decimal_test.go b/types/decimal_test.go index 89a41e96b765..48c691a100dc 100644 --- a/types/decimal_test.go +++ b/types/decimal_test.go @@ -1,7 +1,6 @@ package types import ( - "fmt" "math/big" "testing" From eb039909a8c539c415febf8173b9a0b419c735da Mon Sep 17 00:00:00 2001 From: Alexander Bezobchuk Date: Fri, 3 Jan 2020 09:40:01 -0500 Subject: [PATCH 11/12] Update types/int.go --- types/int.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/int.go b/types/int.go index 67d106030818..caabdb11318c 100644 --- a/types/int.go +++ b/types/int.go @@ -114,7 +114,7 @@ func NewInt(n int64) Int { return Int{big.NewInt(n)} } -// NewInt constructs Int from int64 +// NewIntFromUint64 constructs an Int from a uint64. func NewIntFromUint64(n uint64) Int { b := big.NewInt(0) b.SetUint64(n) From 609779b686f8aa3f10c462e8798e7f99f0166a64 Mon Sep 17 00:00:00 2001 From: Sunny Aggarwal Date: Fri, 3 Jan 2020 14:39:34 -0500 Subject: [PATCH 12/12] CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index be6b7cec3274..4c1b4afb3293 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -170,6 +170,8 @@ that allows for arbitrary vesting periods. * Introduces cli commands and rest routes to query historical information at a given height * (modules) [\#5249](https://github.com/cosmos/cosmos-sdk/pull/5249) Funds are now allowed to be directly sent to the community pool (via the distribution module account). * (keys) [\#4941](https://github.com/cosmos/cosmos-sdk/issues/4941) Introduce keybase option to allow overriding the default private key implementation of a key generated through the `keys add` cli command. +* (types) [\#5447](https://github.com/cosmos/cosmos-sdk/pull/5447) Added `ApproxRoot` function to sdk.Decimal type in order to get the nth root for a decimal number, where n is a positive integer. + * An `ApproxSqrt` function was also added for convenience around the common case of n=2. ### Improvements