| 1 | module unsigned |
| 2 | |
| 3 | import math.bits |
| 4 | |
| 5 | pub const uint256_zero = Uint256{Uint128{}, Uint128{}} |
| 6 | pub const uint256_max = Uint256{uint128_max, uint128_max} |
| 7 | |
| 8 | // Uint256 is an unsigned 256-bit number |
| 9 | pub struct Uint256 { |
| 10 | pub 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 |
| 16 | pub 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 |
| 21 | pub 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` |
| 26 | pub fn uint256_new(lo Uint128, hi Uint128) Uint256 { |
| 27 | return Uint256{lo, hi} |
| 28 | } |
| 29 | |
| 30 | // is_zero checks if specified Uint256 is zero |
| 31 | pub 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 |
| 36 | pub 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 |
| 41 | pub 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 |
| 46 | pub 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 |
| 55 | pub 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 |
| 63 | pub 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 |
| 68 | pub 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 |
| 73 | pub 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 |
| 78 | pub 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 |
| 83 | pub 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 |
| 88 | pub 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 |
| 93 | pub 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 |
| 98 | pub 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 |
| 107 | pub 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 |
| 116 | pub 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 |
| 138 | pub 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 |
| 144 | pub 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 |
| 150 | pub 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 |
| 156 | pub 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 |
| 162 | pub 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 |
| 168 | pub 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 |
| 176 | pub 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 |
| 182 | pub 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 |
| 210 | pub 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 |
| 222 | pub 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 |
| 233 | pub 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 |
| 263 | pub 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 |
| 293 | pub fn (u Uint256) div(v Uint256) Uint256 { |
| 294 | q, _ := u.quo_rem(v) |
| 295 | return q |
| 296 | } |
| 297 | |
| 298 | // div_128 returns u / v |
| 299 | pub 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 |
| 305 | pub 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 |
| 311 | pub 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 |
| 317 | pub 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 |
| 323 | pub 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 |
| 329 | pub 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 |
| 364 | pub 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 |
| 369 | pub 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] |
| 377 | pub 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] |
| 385 | pub 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 |
| 394 | pub 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 |
| 399 | pub 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. |
| 428 | pub 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 |
| 452 | pub fn (u Uint256) / (v Uint256) Uint256 { |
| 453 | return u.div(v) |
| 454 | } |
| 455 | |
| 456 | // % -> returns u % v |
| 457 | pub fn (u Uint256) % (v Uint256) Uint256 { |
| 458 | return u.mod(v) |
| 459 | } |
| 460 | |
| 461 | // + -> returns u + v |
| 462 | pub fn (u Uint256) + (v Uint256) Uint256 { |
| 463 | return u.add(v) |
| 464 | } |
| 465 | |
| 466 | // - -> returns u - v |
| 467 | pub fn (u Uint256) - (v Uint256) Uint256 { |
| 468 | return u.sub(v) |
| 469 | } |
| 470 | |
| 471 | // * -> returns u * v |
| 472 | pub fn (u Uint256) * (v Uint256) Uint256 { |
| 473 | return u.mul(v) |
| 474 | } |
| 475 | |
| 476 | // < -> returns true if u < v |
| 477 | pub fn (u Uint256) < (v Uint256) bool { |
| 478 | return u.cmp(v) == -1 |
| 479 | } |
| 480 | |