-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
big_math.go
126 lines (111 loc) · 3.67 KB
/
big_math.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
// Package bigmath compensates for awkward big.Int API. Can cause an extra allocation or two.
package bigmath
import (
"fmt"
"math/big"
"strings"
)
// ToIntable represents a type that is convertable to a big.Int, ex utils.Big
type ToIntable interface {
ToInt() *big.Int
}
// I returns a new big.Int.
func I() *big.Int { return new(big.Int) }
// Add performs addition with the given values after coercing them to big.Int, or panics if it cannot.
func Add(addend1, addend2 interface{}) *big.Int { return I().Add(bnIfy(addend1), bnIfy(addend2)) }
// Div performs division with the given values after coercing them to big.Int, or panics if it cannot.
func Div(dividend, divisor interface{}) *big.Int { return I().Div(bnIfy(dividend), bnIfy(divisor)) }
// Equal compares the given values after coercing them to big.Int, or panics if it cannot.
func Equal(left, right interface{}) bool { return bnIfy(left).Cmp(bnIfy(right)) == 0 }
// Exp performs modular eponentiation with the given values after coercing them to big.Int, or panics if it cannot.
func Exp(base, exponent, modulus interface{}) *big.Int {
return I().Exp(bnIfy(base), bnIfy(exponent), bnIfy(modulus))
}
// Mul performs multiplication with the given values after coercing them to big.Int, or panics if it cannot.
func Mul(multiplicand, multiplier interface{}) *big.Int {
return I().Mul(bnIfy(multiplicand), bnIfy(multiplier))
}
// Mod performs modulus with the given values after coercing them to big.Int, or panics if it cannot.
func Mod(dividend, divisor interface{}) *big.Int { return I().Mod(bnIfy(dividend), bnIfy(divisor)) }
// Sub performs subtraction with the given values after coercing them to big.Int, or panics if it cannot.
func Sub(minuend, subtrahend interface{}) *big.Int { return I().Sub(bnIfy(minuend), bnIfy(subtrahend)) }
// Max returns the maximum of the two given values after coercing them to big.Int,
// or panics if it cannot.
func Max(x, y interface{}) *big.Int {
xBig := bnIfy(x)
yBig := bnIfy(y)
if xBig.Cmp(yBig) == 1 {
return xBig
}
return yBig
}
// Min returns the min of the two given values after coercing them to big.Int,
// or panics if it cannot.
func Min(x, y interface{}) *big.Int {
xBig := bnIfy(x)
yBig := bnIfy(y)
if xBig.Cmp(yBig) == -1 {
return xBig
}
return yBig
}
// Accumulate returns the sum of the given slice after coercing all elements
// to a big.Int, or panics if it cannot.
func Accumulate(s []interface{}) (r *big.Int) {
r = big.NewInt(0)
for _, e := range s {
r.Add(r, bnIfy(e))
}
return
}
func bnIfy(val interface{}) *big.Int {
if toIntable, ok := val.(ToIntable); ok {
return toIntable.ToInt()
}
switch v := val.(type) {
case uint:
return big.NewInt(0).SetUint64(uint64(v))
case uint8:
return big.NewInt(0).SetUint64(uint64(v))
case uint16:
return big.NewInt(0).SetUint64(uint64(v))
case uint32:
return big.NewInt(0).SetUint64(uint64(v))
case uint64:
return big.NewInt(0).SetUint64(v)
case int:
return big.NewInt(int64(v))
case int8:
return big.NewInt(int64(v))
case int16:
return big.NewInt(int64(v))
case int32:
return big.NewInt(int64(v))
case int64:
return big.NewInt(int64(v))
case float64: // when decoding from db: JSON numbers are floats
return big.NewInt(0).SetUint64(uint64(v))
case string:
if strings.TrimSpace(v) == "" {
panic("invalid big int string")
}
n, ok := big.NewInt(0).SetString(v, 10)
if !ok {
panic(fmt.Sprintf("unable to convert %s to big.Int", v))
}
return n
case *big.Int:
return v
default:
panic(fmt.Sprintf("invalid type for big num conversion: %v", v))
}
}
//nolint
var (
Zero = big.NewInt(0)
One = big.NewInt(1)
Two = big.NewInt(2)
Three = big.NewInt(3)
Four = big.NewInt(4)
Seven = big.NewInt(7)
)