-
-
Notifications
You must be signed in to change notification settings - Fork 14
/
utils.go
99 lines (87 loc) · 2.85 KB
/
utils.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package types
import (
"bytes"
"fmt"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// MaxSortableDec largest sortable sdk.Dec
var MaxSortableDec = sdk.OneDec().Quo(sdk.SmallestDec())
// ValidSortableDec sdk.Dec can't have precision of less than 10^-18
func ValidSortableDec(dec sdk.Dec) bool {
return dec.Abs().LTE(MaxSortableDec)
}
// SortableDecBytes returns a byte slice representation of a Dec that can be sorted.
// Left and right pads with 0s so there are 18 digits to left and right of the decimal point.
// For this reason, there is a maximum and minimum value for this, enforced by ValidSortableDec.
func SortableDecBytes(dec sdk.Dec) []byte {
if !ValidSortableDec(dec) {
panic("dec must be within bounds")
}
// Instead of adding an extra byte to all sortable decs in order to handle max sortable, we just
// makes its bytes be "max" which comes after all numbers in ASCIIbetical order
if dec.Equal(MaxSortableDec) {
return []byte("max")
}
// For the same reason, we make the bytes of minimum sortable dec be --, which comes before all numbers.
if dec.Equal(MaxSortableDec.Neg()) {
return []byte("--")
}
// We move the negative sign to the front of all the left padded 0s, to make negative numbers come before positive numbers
if dec.IsNegative() {
return append([]byte("-"), []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", sdk.Precision*2+1), dec.Abs().String()))...)
}
return []byte(fmt.Sprintf(fmt.Sprintf("%%0%ds", sdk.Precision*2+1), dec.String()))
}
// ParseDecBytes parses a []byte encoded using SortableDecBytes back to sdk.Dec
func ParseDecBytes(db []byte) (sdk.Dec, error) {
strFromDecBytes := strings.Trim(string(db[:]), "0")
if string(strFromDecBytes[0]) == "." {
strFromDecBytes = "0" + strFromDecBytes
}
if string(strFromDecBytes[len(strFromDecBytes)-1]) == "." {
strFromDecBytes = strFromDecBytes + "0"
}
if bytes.Equal(db, []byte("max")) {
return MaxSortableDec, nil
}
if bytes.Equal(db, []byte("--")) {
return MaxSortableDec.Neg(), nil
}
dec, err := sdk.NewDecFromStr(strFromDecBytes)
if err != nil {
return sdk.Dec{}, err
}
return dec, nil
}
// RelativePow raises x to the power of n, where x (and the result, z) are scaled by factor b.
// For example, RelativePow(210, 2, 100) = 441 (2.1^2 = 4.41)
// Only defined for positive ints.
func RelativePow(x sdk.Int, n sdk.Int, b sdk.Int) (z sdk.Int) {
if x.IsZero() {
if n.IsZero() {
z = b // 0^0 = 1
return
}
z = sdk.ZeroInt() // otherwise 0^a = 0
return
}
z = x
if n.Mod(sdk.NewInt(2)).Equal(sdk.ZeroInt()) {
z = b
}
halfOfB := b.Quo(sdk.NewInt(2))
n = n.Quo(sdk.NewInt(2))
for n.GT(sdk.ZeroInt()) {
xSquared := x.Mul(x)
xSquaredRounded := xSquared.Add(halfOfB)
x = xSquaredRounded.Quo(b)
if n.Mod(sdk.NewInt(2)).Equal(sdk.OneInt()) {
zx := z.Mul(x)
zxRounded := zx.Add(halfOfB)
z = zxRounded.Quo(b)
}
n = n.Quo(sdk.NewInt(2))
}
return
}