-
Notifications
You must be signed in to change notification settings - Fork 9
/
bigint.go
302 lines (253 loc) · 7 KB
/
bigint.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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
// Copyright 2019 DxChain, All rights reserved.
// Use of this source code is governed by an Apache
// License 2.0 that can be found in the LICENSE file.
package common
import (
"crypto/rand"
"errors"
"fmt"
"io"
"math"
"math/big"
"github.com/DxChainNetwork/godx/rlp"
)
// Common used BigInt numbers
var (
BigInt0 = NewBigInt(0)
BigInt1 = NewBigInt(1)
)
type BigInt struct {
b big.Int
}
// NewBigInt will be used to convert the int64 data type into BigInt data type
func NewBigInt(x int64) BigInt {
return BigInt{
b: *big.NewInt(x),
}
}
// NewBigIntUint64 will be used to convert the uint64 data type into BigInt data type
func NewBigIntUint64(x uint64) BigInt {
return BigInt{
b: *new(big.Int).SetUint64(x),
}
}
// NewBigIntFloat64 will be used to convert the float64 data type into BigInt data type
func NewBigIntFloat64(x float64) BigInt {
v := int64(x)
return BigInt{
b: *big.NewInt(v),
}
}
// RandomBigIntRange will randomly return a BigInt data based on the range provided
// the input must be greater than 0
func RandomBigIntRange(x BigInt) (random BigInt, err error) {
if x.IsNeg() || x.IsEqual(BigInt0) {
return BigInt{}, errors.New("the input range cannot be negative or 0")
}
randint, err := rand.Int(rand.Reader, x.BigIntPtr())
if err != nil {
return BigInt{}, err
}
random = BigInt{
b: *randint,
}
return
}
// RandomBigInt will randomly return a BigInt data between 0-1000
func RandomBigInt() BigInt {
randint, _ := rand.Int(rand.Reader, big.NewInt(1000))
return BigInt{
b: *randint,
}
}
// String will return the string version of the BigInt
func (x BigInt) String() string {
return x.b.String()
}
// IsNeg will be used to check if the BigInt is negative
func (x BigInt) IsNeg() bool {
if x.Cmp(BigInt0) < 0 {
return true
}
return false
}
// IsEqual will be used to indicate if two BigInt data
// are equivalent to each other. Return true if two BigInt
// are equivalent
func (x BigInt) IsEqual(y BigInt) bool {
if x.Cmp(y) == 0 {
return true
}
return false
}
// Add will perform the addition operation for BigInt data
func (x BigInt) Add(y BigInt) (sum BigInt) {
sum.b.Add(&x.b, &y.b)
return
}
// AddInt64 will perform the addition operation for BigInt and int64 data
func (x BigInt) AddInt64(y int64) (sum BigInt) {
sum.b.Add(&x.b, big.NewInt(y))
return
}
// AddUint64 will perform the addition operation for BigInt and uint64 data
func (x BigInt) AddUint64(y uint64) (sum BigInt) {
sum.b.Add(&x.b, new(big.Int).SetUint64(y))
return
}
// Sub will perform the subtraction operation for BigInt data
func (x BigInt) Sub(y BigInt) (diff BigInt) {
diff.b.Sub(&x.b, &y.b)
return
}
// SubInt64 will perform the subtraction operation for BigInt and int64 data
func (x BigInt) SubInt64(y int64) (diff BigInt) {
diff.b.Sub(&x.b, big.NewInt(y))
return
}
// SubUint64 will perform the subtraction operation for BigInt and uint64 data`
func (x BigInt) SubUint64(y uint64) (diff BigInt) {
diff.b.Sub(&x.b, new(big.Int).SetUint64(y))
return
}
// Mult will perform the multiplication operation for BigInt data
func (x BigInt) Mult(y BigInt) (prod BigInt) {
prod.b.Mul(&x.b, &y.b)
return
}
// MultInt will perform the multiplication operation between BigInt data and int64 data
func (x BigInt) MultInt64(y int64) (prod BigInt) {
prod.b.Mul(&x.b, big.NewInt(y))
return
}
// MultUint64 will perform the multiplication operation between BigInt data and uint64 data
func (x BigInt) MultUint64(y uint64) (prod BigInt) {
prod.b.Mul(&x.b, new(big.Int).SetUint64(y))
return
}
// MultFloat64 will perform the multiplication operation between BigInt data and float64 data
func (x BigInt) MultFloat64(y float64) (prod BigInt) {
// check if y is not a number, multiplication by 1
if math.IsNaN(y) {
y = 1
}
xRat := new(big.Rat).SetInt(&x.b)
yRat := new(big.Rat).SetFloat64(y)
ratProd := new(big.Rat).Mul(xRat, yRat)
prod.b.Div(ratProd.Num(), ratProd.Denom())
return
}
// Div will perform the division operation between BigInt data
func (x BigInt) Div(y BigInt) (quotient BigInt) {
// denominator cannot be 0
if y.Cmp(NewBigInt(0)) == 0 {
y = NewBigInt(1)
}
// division
quotient.b.Div(&x.b, &y.b)
return
}
// DivUint64 will perform the division operation between BigInt data and uint64 data
func (x BigInt) DivUint64(y uint64) (quotient BigInt) {
quotient.b.Div(&x.b, new(big.Int).SetUint64(y))
return
}
// DivNoRemaining will check if the division will give any remainders
func (x BigInt) DivNoRemaining(y uint64) (noRemaining bool) {
// get the x % y
var module BigInt
bigInt := NewBigIntUint64(y)
module.b.Mod(&x.b, &bigInt.b)
// if the result of x % y is 0, meaning the number can be divided completely
if module.IsEqual(BigInt0) {
return true
}
return false
}
// DivWithFloatResult specifies division between two BigInt values and return with float64 result
func (x BigInt) DivWithFloatResult(y BigInt) (quotient float64) {
// making sure that denominator is not 0
if y.IsEqual(BigInt0) {
return
}
// division
quotient, _ = big.NewRat(0, 1).SetFrac(&x.b, &y.b).Float64()
return
}
// DivWithFloatResultUint64 specifies division between BigInt and uint64 values and return with float64 result
func (x BigInt) DivWithFloatResultUint64(y uint64) (quotient float64) {
bigInt := NewBigIntUint64(y)
return x.DivWithFloatResult(bigInt)
}
// Cmp will compare two BigInt Data
// x == y 0
// x > y 1
// x < y -1
func (x BigInt) Cmp(y BigInt) (result int) {
result = x.b.Cmp(&y.b)
return
}
// CmpUint64 will compare BigInt data with Uint64 data
func (x BigInt) CmpUint64(y uint64) (result int) {
result = x.Cmp(NewBigIntUint64(y))
return
}
func (x BigInt) Sign() int {
return x.b.Sign()
}
func (x BigInt) SetInt64(y int64) BigInt {
z := new(big.Int).SetInt64(y)
x.b = *z
return x
}
// float64 will convert the BigInt data type into float64 data type
func (x BigInt) Float64() (result float64) {
f := new(big.Float).SetInt(&x.b)
result, _ = f.Float64()
return
}
// BigIntPtr will return the pointer version of the big.Int
func (x BigInt) BigIntPtr() *big.Int {
return &x.b
}
// PtrBigInt convert the pointer version of big.Int to BigInt type
func PtrBigInt(x *big.Int) (y BigInt) {
y = BigInt{
b: *x,
}
return
}
// MarshalJSON provided JSON encoding rules for BigInt data type
func (x BigInt) MarshalJSON() ([]byte, error) {
return []byte(x.b.String()), nil
}
// UnmarshalJSON provided JSON decoding rules for BigInt data type
func (x *BigInt) UnmarshalJSON(val []byte) error {
if string(val) == "null" {
return nil
}
var y big.Int
_, ok := y.SetString(string(val), 10)
if !ok {
return fmt.Errorf("invalid big integer: %v", y)
}
x.b = y
return nil
}
// EncodeRLP encode a BigInt to rlp bytes
func (x BigInt) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, x.b.String())
}
// DecodeRLP decode rlp bytes to a BigInt
func (x *BigInt) DecodeRLP(st *rlp.Stream) error {
var stringFormat string
if err := st.Decode(&stringFormat); err != nil {
return err
}
var y big.Int
if _, ok := y.SetString(stringFormat, 10); !ok {
return fmt.Errorf("invalid big integer: %v", y)
}
x.b = y
return nil
}