forked from prysmaticlabs/prysm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmath_helper.go
185 lines (162 loc) · 4.67 KB
/
math_helper.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// Package math includes important helpers for Ethereum such as fast integer square roots.
package math
import (
"errors"
stdmath "math"
"math/bits"
"github.com/thomaso-mirodin/intmath/u64"
)
func init() {
// The Int function assumes that the operating system is 64 bit. In any case, Ethereum
// consensus layer uses 64 bit values almost exclusively so 64 bit OS requirement should
// already be established. This panic is a strict fail fast feedback to alert 32 bit users
// that they are not supported.
if stdmath.MaxUint < stdmath.MaxUint64 {
panic("Prysm is only supported on 64 bit OS")
}
}
// ErrOverflow occurs when an operation exceeds max or minimum values.
var (
ErrOverflow = errors.New("integer overflow")
ErrDivByZero = errors.New("integer divide by zero")
ErrMulOverflow = errors.New("multiplication overflows")
ErrAddOverflow = errors.New("addition overflows")
ErrSubUnderflow = errors.New("subtraction underflow")
)
// Common square root values.
var squareRootTable = map[uint64]uint64{
4: 2,
16: 4,
64: 8,
256: 16,
1024: 32,
4096: 64,
16384: 128,
65536: 256,
262144: 512,
1048576: 1024,
4194304: 2048,
}
// IntegerSquareRoot defines a function that returns the
// largest possible integer root of a number using go's standard library.
func IntegerSquareRoot(n uint64) uint64 {
if v, ok := squareRootTable[n]; ok {
return v
}
// Golang floating point precision may be lost above 52 bits, so we use a
// non floating point method. u64.Sqrt is about x2.5 slower than math.Sqrt.
if n >= 1<<52 {
return u64.Sqrt(n)
}
return uint64(stdmath.Sqrt(float64(n)))
}
// CeilDiv8 divides the input number by 8
// and takes the ceiling of that number.
func CeilDiv8(n int) int {
ret := n / 8
if n%8 > 0 {
ret++
}
return ret
}
// IsPowerOf2 returns true if n is an
// exact power of two. False otherwise.
func IsPowerOf2(n uint64) bool {
return n != 0 && (n&(n-1)) == 0
}
// PowerOf2 returns an integer that is the provided
// exponent of 2. Can only return powers of 2 till 63,
// after that it overflows
func PowerOf2(n uint64) uint64 {
if n >= 64 {
panic("integer overflow")
}
return 1 << n
}
// Max returns the larger integer of the two
// given ones.This is used over the Max function
// in the standard math library because that max function
// has to check for some special floating point cases
// making it slower by a magnitude of 10.
func Max(a, b uint64) uint64 {
if a > b {
return a
}
return b
}
// Min returns the smaller integer of the two
// given ones. This is used over the Min function
// in the standard math library because that min function
// has to check for some special floating point cases
// making it slower by a magnitude of 10.
func Min(a, b uint64) uint64 {
if a < b {
return a
}
return b
}
// Mul64 multiples 2 64-bit unsigned integers and checks if they
// lead to an overflow. If they do not, it returns the result
// without an error.
func Mul64(a, b uint64) (uint64, error) {
overflows, val := bits.Mul64(a, b)
if overflows > 0 {
return 0, errors.New("multiplication overflows")
}
return val, nil
}
// Div64 divides two 64-bit unsigned integers and checks for errors.
func Div64(a, b uint64) (uint64, error) {
if b == 0 {
return 0, ErrDivByZero
}
val, _ := bits.Div64(0, a, b)
return val, nil
}
// Add64 adds 2 64-bit unsigned integers and checks if they
// lead to an overflow. If they do not, it returns the result
// without an error.
func Add64(a, b uint64) (uint64, error) {
res, carry := bits.Add64(a, b, 0 /* carry */)
if carry > 0 {
return 0, errors.New("addition overflows")
}
return res, nil
}
// Sub64 subtracts two 64-bit unsigned integers and checks for errors.
func Sub64(a, b uint64) (uint64, error) {
res, borrow := bits.Sub64(a, b, 0 /* borrow */)
if borrow > 0 {
return 0, errors.New("subtraction underflow")
}
return res, nil
}
// Mod64 finds remainder of division of two 64-bit unsigned integers and checks for errors.
func Mod64(a, b uint64) (uint64, error) {
if b == 0 {
return 0, ErrDivByZero
}
_, val := bits.Div64(0, a, b)
return val, nil
}
// Int returns the integer value of the uint64 argument. If there is an overlow, then an error is
// returned.
func Int(u uint64) (int, error) {
if u > stdmath.MaxInt {
return 0, ErrOverflow
}
return int(u), nil // lint:ignore uintcast -- This is the preferred method of casting uint64 to int.
}
// AddInt adds two or more integers and checks for integer overflows.
func AddInt(i ...int) (int, error) {
var sum int
for _, ii := range i {
if ii > 0 && sum > stdmath.MaxInt-ii {
return 0, ErrOverflow
} else if ii < 0 && sum < stdmath.MinInt-ii {
return 0, ErrOverflow
}
sum += ii
}
return sum, nil
}