v2 / vlib / math / unsigned / uint256.v
479 lines · 406 sloc · 12.01 KB · e2e5cf8db56f3562c7baa735061690be936bdf3e
Raw
1module unsigned
2
3import math.bits
4
5pub const uint256_zero = Uint256{Uint128{}, Uint128{}}
6pub const uint256_max = Uint256{uint128_max, uint128_max}
7
8// Uint256 is an unsigned 256-bit number
9pub struct Uint256 {
10pub mut:
11 lo Uint128 = uint128_zero // lower 128 bit half
12 hi Uint128 = uint128_zero // upper 128 bit half
13}
14
15// uint256_from_128 creates a new `unsigned.Uint256` from the given Uint128 value
16pub fn uint256_from_128(v Uint128) Uint256 {
17 return Uint256{v, uint128_zero}
18}
19
20// uint256_from_64 creates a new `unsigned.Uint256` from the given u64 value
21pub fn uint256_from_64(v u64) Uint256 {
22 return uint256_from_128(uint128_from_64(v))
23}
24
25// uint256_new creates new Uint256 with given `lo` and `hi`
26pub fn uint256_new(lo Uint128, hi Uint128) Uint256 {
27 return Uint256{lo, hi}
28}
29
30// is_zero checks if specified Uint256 is zero
31pub fn (u Uint256) is_zero() bool {
32 return u.lo.is_zero() && u.hi.is_zero()
33}
34
35// equals checks if the two Uint256 values match one another
36pub fn (u Uint256) equals(v Uint256) bool {
37 return u.lo.equals(v.lo) && u.hi.equals(v.hi)
38}
39
40// equals_128 checks if the Uint256 value matches the Uint128 value
41pub fn (u Uint256) equals_128(v Uint128) bool {
42 return u.lo.equals(v) && u.hi.is_zero()
43}
44
45// cmp returns 1 if u is greater than v, -1 if u is less than v, or 0 if equal
46pub fn (u Uint256) cmp(v Uint256) int {
47 h := u.hi.cmp(v.hi)
48 if h != 0 {
49 return h
50 }
51 return u.lo.cmp(v.lo)
52}
53
54// cmp_128 returns 1 if u is greater than v (Uint128), -1 if u is less than v, or 0 if equal
55pub fn (u Uint256) cmp_128(v Uint128) int {
56 if !u.hi.is_zero() {
57 return 1
58 }
59 return u.lo.cmp(v)
60}
61
62// not returns a binary negation of the Uint256 value
63pub fn (u Uint256) not() Uint256 {
64 return Uint256{u.lo.not(), u.hi.not()}
65}
66
67// and returns a Uint256 value that is the bitwise and of u and v
68pub fn (u Uint256) and(v Uint256) Uint256 {
69 return Uint256{u.lo.and(v.lo), u.hi.and(v.hi)}
70}
71
72// and_128 returns a Uint256 value that is the bitwise and of u and v, which is a Uint128
73pub fn (u Uint256) and_128(v Uint128) Uint256 {
74 return Uint256{u.lo.and(v), uint128_zero}
75}
76
77// or_ returns a Uint256 value that is the bitwise or of u and v
78pub fn (u Uint256) or_(v Uint256) Uint256 {
79 return Uint256{u.lo.or_(v.lo), u.hi.or_(v.hi)}
80}
81
82// or_128 returns a Uint256 value that is the bitwise or of u and v, which is a Uint128
83pub fn (u Uint256) or_128(v Uint128) Uint256 {
84 return Uint256{u.lo.or_(v), u.hi}
85}
86
87// xor returns a Uint256 value that is the bitwise xor of u and v
88pub fn (u Uint256) xor(v Uint256) Uint256 {
89 return Uint256{u.lo.xor(v.lo), u.hi.xor(v.hi)}
90}
91
92// xor_128 returns a Uint256 value that is the bitwise xor of u and v, which is a Uint128
93pub fn (u Uint256) xor_128(v Uint128) Uint256 {
94 return Uint256{u.lo.xor(v), u.hi}
95}
96
97// add_256 return u + v and the carry
98pub fn add_256(x Uint256, y Uint256, carry u64) (Uint256, u64) {
99 mut sum := Uint256{}
100 mut carry_out := u64(0)
101 sum.lo, carry_out = add_128(x.lo, y.lo, carry)
102 sum.hi, carry_out = add_128(x.hi, y.hi, carry_out)
103 return sum, carry_out
104}
105
106// sub_256 returns u - v and the borrow
107pub fn sub_256(x Uint256, y Uint256, borrow u64) (Uint256, u64) {
108 mut diff := Uint256{}
109 mut borrow_out := u64(0)
110 diff.lo, borrow_out = sub_128(x.lo, y.lo, borrow)
111 diff.hi, borrow_out = sub_128(x.hi, y.hi, borrow_out)
112 return diff, borrow_out
113}
114
115// mul_256 returns u x v
116pub fn mul_256(x Uint256, y Uint256) (Uint256, Uint256) {
117 mut hi := Uint256{}
118 mut lo := Uint256{}
119
120 lo.hi, lo.lo = mul_128(x.lo, y.lo)
121 hi.hi, hi.lo = mul_128(x.hi, y.hi)
122 t0, t1 := mul_128(x.lo, y.hi)
123 t2, t3 := mul_128(x.hi, y.lo)
124
125 mut c0 := u64(0)
126 mut c1 := u64(0)
127
128 lo.hi, c0 = add_128(lo.hi, t1, 0)
129 lo.hi, c1 = add_128(lo.hi, t3, 0)
130 hi.lo, c0 = add_128(hi.lo, t0, c0)
131 hi.lo, c1 = add_128(hi.lo, t2, c1)
132 hi.hi = hi.hi.add_64(c0 + c1)
133
134 return hi, lo
135}
136
137// add returns a Uint256 that is equal to u+v
138pub fn (u Uint256) add(v Uint256) Uint256 {
139 sum, _ := add_256(u, v, 0)
140 return sum
141}
142
143// overflowing_add returns u + v even if result size > 256
144pub fn (u Uint256) overflowing_add(v Uint256) (Uint256, u64) {
145 sum, overflow := add_256(u, v, 0)
146 return sum, overflow
147}
148
149// add_128 returns a Uint256 that is equal to u+v, v being a Uint128
150pub fn (u Uint256) add_128(v Uint128) Uint256 {
151 lo, c0 := add_128(u.lo, v, 0)
152 return Uint256{lo, u.hi.add_64(c0)}
153}
154
155// sub returns a Uint256 that is equal to u-v
156pub fn (u Uint256) sub(v Uint256) Uint256 {
157 diff, _ := sub_256(u, v, 0)
158 return diff
159}
160
161// sub_128 returns a Uint256 that is equal to u-v, v being a Uint128
162pub fn (u Uint256) sub_128(v Uint128) Uint256 {
163 lo, b0 := sub_128(u.lo, v, 0)
164 return Uint256{lo, u.hi.sub_64(b0)}
165}
166
167// mul returns a Uint256 that is eqal to u*v
168pub fn (u Uint256) mul(v Uint256) Uint256 {
169 mut hi, mut lo := mul_128(u.lo, v.lo)
170 hi = hi.add(u.hi.mul(v.lo))
171 hi = hi.add(u.lo.mul(v.hi))
172 return Uint256{lo, hi}
173}
174
175// mul_128 returns a Uint256 that is eqal to u*v, v being a Uint128
176pub fn (u Uint256) mul_128(v Uint128) Uint256 {
177 hi, lo := mul_128(u.lo, v)
178 return Uint256{lo, hi.add(u.hi.mul(v))}
179}
180
181// quo_rem returns q = u/v and r = u%v
182pub fn (u Uint256) quo_rem(v Uint256) (Uint256, Uint256) {
183 if v.hi.is_zero() && v.lo.hi == 0 {
184 q, r := u.quo_rem_64(v.lo.lo)
185 return q, uint256_from_64(r)
186 }
187
188 if v.hi.is_zero() {
189 q, r := u.quo_rem_128(v.lo)
190 return q, uint256_from_128(r)
191 }
192
193 n := u64(v.hi.leading_zeros())
194 u1, v1 := u.rsh(1), v.lsh(u32(n))
195 mut tq, _ := div_128(u1.hi, u1.lo, v1.hi)
196 tq = tq.rsh(u32(127 - n))
197 if !tq.is_zero() {
198 tq = tq.sub_64(1)
199 }
200
201 mut q, mut r := uint256_from_128(tq), u.sub(v.mul_128(tq))
202 if r.cmp(v) >= 0 {
203 q = q.add_128(Uint128{1, 0})
204 r = r.sub(v)
205 }
206 return q, r
207}
208
209// quo_rem_128 returns q = u/v and r = u%v
210pub fn (u Uint256) quo_rem_128(v Uint128) (Uint256, Uint128) {
211 if u.hi.cmp(v) < 0 {
212 lo, r := div_128(u.hi, u.lo, v)
213 return Uint256{lo, uint128_zero}, r
214 }
215
216 hi, r := div_128(uint128_zero, u.hi, v)
217 lo, r2 := div_128(r, u.lo, v)
218 return Uint256{lo, hi}, r2
219}
220
221// quo_rem_64 returns q = u/v and r = u%v
222pub fn (u Uint256) quo_rem_64(v u64) (Uint256, u64) {
223 mut q := Uint256{}
224 mut r := u64(0)
225 q.hi.hi, r = bits.div_64(r, u.hi.hi, v)
226 q.hi.lo, r = bits.div_64(r, u.hi.lo, v)
227 q.lo.hi, r = bits.div_64(r, u.lo.hi, v)
228 q.lo.lo, r = bits.div_64(r, u.lo.lo, v)
229 return q, r
230}
231
232// rsh returns a new Uint256 that has been right bit shifted
233pub fn (u Uint256) rsh(n u32) Uint256 {
234 mut s := Uint256{}
235 if n == 0 {
236 s.lo = u.lo
237 s.hi = u.hi
238 } else if n >= 256 {
239 s.lo = uint128_zero
240 s.hi = uint128_zero
241 } else if n == 128 {
242 s.hi = uint128_zero
243 s.lo = u.hi
244 } else if n > 128 {
245 s.hi = uint128_zero
246 s.lo = u.hi.rsh(n - 128)
247 } else if n == 64 {
248 s.lo = Uint128{u.lo.hi, u.hi.lo}
249 s.hi = Uint128{u.hi.hi, 0}
250 } else if n > 64 {
251 shift := n - 64
252 s.lo =
253 Uint128{u.lo.hi >> shift | u.hi.lo << (64 - shift), u.hi.lo >> shift | u.hi.hi << (64 - shift)}
254 s.hi = Uint128{u.hi.hi >> shift, 0}
255 } else {
256 s.lo = Uint128{u.lo.lo >> n | u.lo.hi << (64 - n), u.lo.hi >> n | u.hi.lo << (64 - n)}
257 s.hi = Uint128{u.hi.lo >> n | u.hi.hi << (64 - n), u.hi.hi >> n}
258 }
259 return s
260}
261
262// lsh returns a new Uint256 that has been left bit shifted
263pub fn (u Uint256) lsh(n u32) Uint256 {
264 mut s := Uint256{}
265 if n == 0 {
266 s.lo = u.lo
267 s.hi = u.hi
268 } else if n >= 256 {
269 s.lo = uint128_zero
270 s.hi = uint128_zero
271 } else if n == 128 {
272 s.lo = uint128_zero
273 s.hi = u.lo
274 } else if n > 128 {
275 s.lo = uint128_zero
276 s.hi = u.lo.lsh(n - 128)
277 } else if n == 64 {
278 s.lo = Uint128{0, u.lo.lo}
279 s.hi = Uint128{u.lo.hi, u.hi.lo}
280 } else if n > 64 {
281 shift := n - 64
282 s.lo = Uint128{0, u.lo.lo << shift}
283 s.hi =
284 Uint128{u.lo.lo >> (64 - shift) | u.lo.hi << shift, u.lo.hi >> (64 - shift) | u.hi.lo << shift}
285 } else {
286 s.lo = Uint128{u.lo.lo << n, u.lo.hi << n | u.lo.lo >> (64 - n)}
287 s.hi = Uint128{u.hi.lo << n | u.lo.hi >> (64 - n), u.hi.hi << n | u.hi.lo >> (64 - n)}
288 }
289 return s
290}
291
292// div returns u / v
293pub fn (u Uint256) div(v Uint256) Uint256 {
294 q, _ := u.quo_rem(v)
295 return q
296}
297
298// div_128 returns u / v
299pub fn (u Uint256) div_128(v Uint128) Uint256 {
300 q, _ := u.quo_rem_128(v)
301 return q
302}
303
304// div_64 returns u / v
305pub fn (u Uint256) div_64(v u64) Uint256 {
306 q, _ := u.quo_rem_64(v)
307 return q
308}
309
310// mod returns r = u % v
311pub fn (u Uint256) mod(v Uint256) Uint256 {
312 _, r := u.quo_rem(v)
313 return r
314}
315
316// mod_128 returns r = u % v
317pub fn (u Uint256) mod_128(v Uint128) Uint128 {
318 _, r := u.quo_rem_128(v)
319 return r
320}
321
322// mod_64 returns r = u % v
323pub fn (u Uint256) mod_64(v u64) u64 {
324 _, r := u.quo_rem_64(v)
325 return r
326}
327
328// rotate_left returns a new Uint256 that has been left bit shifted
329pub fn (u Uint256) rotate_left(k int) Uint256 {
330 mut n := u32(k) & 255
331 if n < 64 {
332 if n == 0 {
333 return u
334 }
335
336 return Uint256{Uint128{u.lo.lo << n | u.hi.hi >> (64 - n), u.lo.hi << n | u.lo.lo >> (64 - n)}, Uint128{u.hi.lo << n | u.lo.hi >> (64 - n), u.hi.hi << n | u.hi.lo >> (64 - n)}}
337 }
338 n -= 64
339 if n < 64 {
340 if n == 0 {
341 return Uint256{Uint128{u.hi.hi, u.lo.lo}, Uint128{u.lo.hi, u.hi.lo}}
342 }
343
344 return Uint256{Uint128{u.hi.hi << n | u.hi.lo >> (64 - n), u.lo.lo << n | u.hi.hi >> (64 - n)}, Uint128{u.lo.hi << n | u.lo.lo >> (64 - n), u.hi.lo << n | u.lo.hi >> (64 - n)}}
345 }
346
347 n -= 64
348 if n < 64 {
349 if n == 0 {
350 return Uint256{u.hi, u.lo}
351 }
352
353 return Uint256{Uint128{u.hi.lo << n | u.lo.hi >> (64 - n), u.hi.hi << n | u.hi.lo >> (64 - n)}, Uint128{u.lo.lo << n | u.hi.hi >> (64 - n), u.lo.hi << n | u.lo.lo >> (64 - n)}}
354 }
355 n -= 64
356 if n == 0 {
357 return Uint256{Uint128{u.lo.hi, u.hi.lo}, Uint128{u.hi.hi, u.lo.lo}}
358 }
359
360 return Uint256{Uint128{u.lo.hi << n | u.lo.lo >> (64 - n), u.hi.lo << n | u.lo.hi >> (64 - n)}, Uint128{u.hi.hi << n | u.hi.lo >> (64 - n), u.lo.lo << n | u.hi.hi >> (64 - n)}}
361}
362
363// rotate_right returns a new Uint256 that has been right bit shifted
364pub fn (u Uint256) rotate_right(k int) Uint256 {
365 return u.rotate_left(-k)
366}
367
368// len returns the length of the binary value without the leading zeros
369pub fn (u Uint256) len() int {
370 if !u.hi.is_zero() {
371 return 128 + u.hi.len()
372 }
373 return u.lo.len()
374}
375
376// leading_zeros returns the number of 0s at the beginning of the binary value of the Uint256 value [0, 256]
377pub fn (u Uint256) leading_zeros() int {
378 if !u.hi.is_zero() {
379 return u.hi.leading_zeros()
380 }
381 return 128 + u.lo.leading_zeros()
382}
383
384// trailing_zeros returns the number of 0s at the end of the binary value of the Uint256 value [0,256]
385pub fn (u Uint256) trailing_zeros() int {
386 if !u.lo.is_zero() {
387 return u.lo.trailing_zeros()
388 }
389
390 return 128 + u.hi.trailing_zeros()
391}
392
393// ones_count returns the number of ones in the binary value of the Uint256 value
394pub fn (u Uint256) ones_count() int {
395 return u.lo.ones_count() + u.hi.ones_count()
396}
397
398// str returns the decimal representation of the unsigned integer
399pub fn (u_ Uint256) str() string {
400 mut u := u_
401 if u.hi.is_zero() {
402 if u.lo.is_zero() {
403 return '0'
404 }
405 return u.lo.str()
406 }
407
408 mut buf :=
409 '000000000000000000000000000000000000000000000000000000000000000000000000000000'.bytes()
410
411 for i := buf.len; true; i -= 19 {
412 q, mut r := u.quo_rem_64(u64(1e19))
413 mut n := 0
414 for ; r != 0; r /= 10 {
415 n++
416 buf[i - n] += u8(r % 10)
417 }
418 if q.is_zero() {
419 return buf[i - n..].bytestr()
420 }
421 u = q
422 }
423 return ''
424}
425
426// uint256_from_dec_str creates a new `unsigned.Uint256` from the given string if possible
427// The `_` character is allowed as a separator.
428pub fn uint256_from_dec_str(value string) !Uint256 {
429 mut res := uint256_zero
430 underscore := `_`
431
432 for b_ in value {
433 b := b_ - `0`
434 if b > 9 {
435 // allow _ as a separator in decimal strings
436 if b_ == underscore {
437 continue
438 }
439
440 return error('invalid character "${b}"')
441 }
442
443 r := res.mul_128(uint128_from_64(10))
444
445 r2 := r.add_128(uint128_from_64(u64(b)))
446 res = r2
447 }
448 return res
449}
450
451// / -> returns u / v
452pub fn (u Uint256) / (v Uint256) Uint256 {
453 return u.div(v)
454}
455
456// % -> returns u % v
457pub fn (u Uint256) % (v Uint256) Uint256 {
458 return u.mod(v)
459}
460
461// + -> returns u + v
462pub fn (u Uint256) + (v Uint256) Uint256 {
463 return u.add(v)
464}
465
466// - -> returns u - v
467pub fn (u Uint256) - (v Uint256) Uint256 {
468 return u.sub(v)
469}
470
471// * -> returns u * v
472pub fn (u Uint256) * (v Uint256) Uint256 {
473 return u.mul(v)
474}
475
476// < -> returns true if u < v
477pub fn (u Uint256) < (v Uint256) bool {
478 return u.cmp(v) == -1
479}
480