math: add an `unsigned` module, implementing Uint128, Uint256 and methods on them (#13186)
parent
31615d67c4
commit
8de1934f51
|
@ -0,0 +1,462 @@
|
|||
module uint
|
||||
|
||||
import math.bits
|
||||
import encoding.binary
|
||||
|
||||
pub struct Uint128 {
|
||||
pub mut:
|
||||
lo u64
|
||||
hi u64
|
||||
}
|
||||
|
||||
pub const (
|
||||
uint128_zero = Uint128{}
|
||||
uint128_max = Uint128{18446744073709551615, 18446744073709551615}
|
||||
)
|
||||
|
||||
// is_zero returns true if u == 0
|
||||
pub fn (u Uint128) is_zero() bool {
|
||||
return u == Uint128{}
|
||||
}
|
||||
|
||||
// equals returns true if u == v.
|
||||
//
|
||||
// Uint128 values can be compared directly with ==, but use of the Equals method
|
||||
// is preferred for consistency.
|
||||
pub fn (u Uint128) equals(v Uint128) bool {
|
||||
return u == v
|
||||
}
|
||||
|
||||
// equals_64 returns true if u == v
|
||||
pub fn (u Uint128) equals_64(v u64) bool {
|
||||
return u.lo == v && u.hi == 0
|
||||
}
|
||||
|
||||
// cmp compares u and v and returns:
|
||||
//
|
||||
// -1 if u < v
|
||||
// 0 if u == v
|
||||
// +1 if u > v
|
||||
//
|
||||
pub fn (u Uint128) cmp(v Uint128) int {
|
||||
if u == v {
|
||||
return 0
|
||||
} else if u.hi < v.hi || (u.hi == v.hi && u.lo < v.lo) {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// cmp_64 compares u and v and returns:
|
||||
//
|
||||
// -1 if u < v
|
||||
// 0 if u == v
|
||||
// +1 if u > v
|
||||
//
|
||||
pub fn (u Uint128) cmp_64(v u64) int {
|
||||
if u.hi == 0 && u.lo == v {
|
||||
return 0
|
||||
} else if u.hi == 0 && u.lo < v {
|
||||
return -1
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// and returns u & v
|
||||
pub fn (u Uint128) and(v Uint128) Uint128 {
|
||||
return Uint128{u.lo & v.lo, u.hi & v.hi}
|
||||
}
|
||||
|
||||
// and_64 rreturns u & v
|
||||
pub fn (u Uint128) and_64(v u64) Uint128 {
|
||||
return Uint128{u.lo & v, u.hi & 0}
|
||||
}
|
||||
|
||||
// or returns u | v
|
||||
pub fn (u Uint128) or_(v Uint128) Uint128 {
|
||||
return Uint128{u.lo | v.lo, u.hi | v.hi}
|
||||
}
|
||||
|
||||
// or returns u | v
|
||||
pub fn (u Uint128) or_64(v u64) Uint128 {
|
||||
return Uint128{u.lo | v, u.hi | 0}
|
||||
}
|
||||
|
||||
// xor returns u ^ v
|
||||
pub fn (u Uint128) xor(v Uint128) Uint128 {
|
||||
return Uint128{u.lo ^ v.lo, u.hi ^ v.hi}
|
||||
}
|
||||
|
||||
// xor_64 returns u ^ v
|
||||
pub fn (u Uint128) xor_64(v u64) Uint128 {
|
||||
return Uint128{u.lo ^ v, u.hi ^ 0}
|
||||
}
|
||||
|
||||
// add returns u + v with wraparound semantics
|
||||
pub fn (u Uint128) add(v Uint128) Uint128 {
|
||||
lo, carry := bits.add_64(u.lo, v.lo, 0)
|
||||
hi, _ := bits.add_64(u.hi, v.hi, carry)
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
pub fn add_128(x Uint128, y Uint128, carry u64) (Uint128, u64) {
|
||||
mut sum := Uint128{}
|
||||
mut carry_out := u64(0)
|
||||
sum.lo, carry_out = bits.add_64(x.lo, y.lo, carry)
|
||||
sum.hi, carry_out = bits.add_64(x.hi, y.hi, carry_out)
|
||||
return sum, carry_out
|
||||
}
|
||||
|
||||
pub fn sub_128(x Uint128, y Uint128, borrow u64) (Uint128, u64) {
|
||||
mut diff := Uint128{}
|
||||
mut borrow_out := u64(0)
|
||||
diff.lo, borrow_out = bits.sub_64(x.lo, y.lo, borrow)
|
||||
diff.hi, borrow_out = bits.sub_64(x.hi, y.hi, borrow_out)
|
||||
return diff, borrow_out
|
||||
}
|
||||
|
||||
pub fn mul_128(x Uint128, y Uint128) (Uint128, Uint128) {
|
||||
mut lo := Uint128{}
|
||||
mut hi := Uint128{}
|
||||
lo.hi, lo.lo = bits.mul_64(x.lo, y.lo)
|
||||
hi.hi, hi.lo = bits.mul_64(x.hi, y.hi)
|
||||
t0, t1 := bits.mul_64(x.lo, y.hi)
|
||||
t2, t3 := bits.mul_64(x.hi, y.lo)
|
||||
|
||||
mut c0 := u64(0)
|
||||
mut c1 := u64(0)
|
||||
lo.hi, c0 = bits.add_64(lo.hi, t1, 0)
|
||||
lo.hi, c1 = bits.add_64(lo.hi, t3, 0)
|
||||
hi.lo, c0 = bits.add_64(hi.lo, t0, c0)
|
||||
hi.lo, c1 = bits.add_64(hi.lo, t2, c1)
|
||||
hi.hi += c0 + c1
|
||||
return hi, lo
|
||||
}
|
||||
|
||||
pub fn div_128(hi Uint128, lo Uint128, y_ Uint128) (Uint128, Uint128) {
|
||||
mut y := y_
|
||||
if y.is_zero() {
|
||||
panic('integer divide by zero')
|
||||
}
|
||||
|
||||
if y.cmp(hi) <= 0 {
|
||||
panic('integer overflow')
|
||||
}
|
||||
|
||||
s := u32(y.leading_zeros())
|
||||
y = y.lsh(s)
|
||||
|
||||
un32 := hi.lsh(s).or_(lo.rsh(128 - s))
|
||||
un10 := lo.lsh(s)
|
||||
mut q1, rhat := un32.quo_rem_64(y.hi)
|
||||
mut r1 := uint128_from_64(rhat)
|
||||
tmp := Uint128{r1.lo, un10.hi}
|
||||
for q1.hi != 0 || q1.mul_64(y.lo).cmp(tmp) > 0 {
|
||||
q1 = q1.sub_64(1)
|
||||
r1 = r1.add_64(y.hi)
|
||||
if r1.hi != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
un21 := Uint128{un32.lo, un10.hi}.sub(q1.mul(y))
|
||||
mut q0, rhat2 := un21.quo_rem_64(y.hi)
|
||||
mut r0 := uint128_from_64(rhat2)
|
||||
tmp2 := Uint128{r0.lo, un10.lo}
|
||||
for q0.hi != 0 || q0.mul_64(y.lo).cmp(tmp2) > 0 {
|
||||
q0 = q0.sub_64(1)
|
||||
r0 = r0.add_64(y.hi)
|
||||
if r0.hi != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return Uint128{q1.lo, q0.lo}, Uint128{un21.lo, un10.lo}.sub(q0.mul(y)).rsh(s)
|
||||
}
|
||||
|
||||
// add_64 returns u + v with wraparound semantics
|
||||
pub fn (u Uint128) add_64(v u64) Uint128 {
|
||||
lo, carry := bits.add_64(u.lo, v, 0)
|
||||
hi := u.hi + carry
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
// sub returns u - v with wraparound semantics
|
||||
pub fn (u Uint128) sub(v Uint128) Uint128 {
|
||||
lo, borrow := bits.sub_64(u.lo, v.lo, 0)
|
||||
hi, _ := bits.sub_64(u.hi, v.hi, borrow)
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
// sub_64 returns u - v with wraparound semantics
|
||||
pub fn (u Uint128) sub_64(v u64) Uint128 {
|
||||
lo, borrow := bits.sub_64(u.lo, v, 0)
|
||||
hi := u.hi - borrow
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
// mul returns u * v with wraparound semantics
|
||||
pub fn (u Uint128) mul(v Uint128) Uint128 {
|
||||
mut hi, lo := bits.mul_64(u.lo, v.lo)
|
||||
hi += u.hi * v.lo + u.lo * v.hi
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
// mul_64 returns u * v with wraparound semantics
|
||||
pub fn (u Uint128) mul_64(v u64) Uint128 {
|
||||
mut hi, lo := bits.mul_64(u.lo, v)
|
||||
hi += u.hi * v
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
pub fn (u Uint128) overflowing_mul_64(v u64) (Uint128, bool) {
|
||||
hi, lo := bits.mul_64(u.lo, v)
|
||||
p0, p1 := bits.mul_64(u.hi, v)
|
||||
hi2, c0 := bits.add_64(hi, p1, 0)
|
||||
|
||||
return Uint128{lo, hi2}, p0 != 0 || c0 != 0
|
||||
}
|
||||
|
||||
pub fn (u Uint128) overflowing_add_64(v u64) (Uint128, u64) {
|
||||
lo, carry := bits.add_64(u.lo, v, 0)
|
||||
hi, carry2 := bits.add_64(u.hi, 0, carry)
|
||||
|
||||
return Uint128{lo, hi}, carry2
|
||||
}
|
||||
|
||||
// div returns u / v
|
||||
pub fn (u Uint128) div(v Uint128) Uint128 {
|
||||
q, _ := u.quo_rem(v)
|
||||
return q
|
||||
}
|
||||
|
||||
// mod returns r = u % v
|
||||
pub fn (u Uint128) mod(v Uint128) Uint128 {
|
||||
_, r := u.quo_rem(v)
|
||||
return r
|
||||
}
|
||||
|
||||
// mod_64 returns r = u % v
|
||||
pub fn (u Uint128) mod_64(v u64) u64 {
|
||||
_, r := u.quo_rem_64(v)
|
||||
return r
|
||||
}
|
||||
|
||||
// quo_rem_64 returns q = u/v and r = u%v
|
||||
pub fn (u Uint128) quo_rem_64(v u64) (Uint128, u64) {
|
||||
if u.hi < v {
|
||||
mut r := u64(0)
|
||||
mut q := Uint128{0, 0}
|
||||
q.lo, r = bits.div_64(u.hi, u.lo, v)
|
||||
|
||||
return q, r
|
||||
} else {
|
||||
mut q := Uint128{0, 0}
|
||||
mut r := u64(0)
|
||||
mut r2 := u64(0)
|
||||
q.hi, r = bits.div_64(0, u.hi, v)
|
||||
q.lo, r2 = bits.div_64(r, u.lo, v)
|
||||
return q, r2
|
||||
}
|
||||
}
|
||||
|
||||
// quo_rem returns q = u/v and r = u%v
|
||||
pub fn (u Uint128) quo_rem(v Uint128) (Uint128, Uint128) {
|
||||
mut q := Uint128{}
|
||||
mut r := Uint128{}
|
||||
if v.hi == 0 {
|
||||
mut r64 := u64(0)
|
||||
q, r64 = u.quo_rem_64(v.lo)
|
||||
r = Uint128{r64, 0}
|
||||
} else {
|
||||
n := bits.leading_zeros_64(v.hi)
|
||||
v1 := v.lsh(u32(n))
|
||||
u1 := v.rsh(1)
|
||||
|
||||
mut tq, _ := bits.div_64(u1.hi, u1.lo, v1.hi)
|
||||
tq >>= u64(64 - n)
|
||||
if tq != 0 {
|
||||
tq -= 1
|
||||
}
|
||||
|
||||
q = Uint128{tq, 0}
|
||||
r = u - v.mul_64(tq)
|
||||
|
||||
if r.cmp(v) >= 0 {
|
||||
q = q.add_64(1)
|
||||
r = r - v
|
||||
}
|
||||
}
|
||||
|
||||
return q, r
|
||||
}
|
||||
|
||||
// lsh returns u << n
|
||||
pub fn (u Uint128) lsh(n u32) Uint128 {
|
||||
mut s := Uint128{}
|
||||
if n > 64 {
|
||||
s.lo = 0
|
||||
s.hi = u.lo << (n - 64)
|
||||
} else {
|
||||
s.lo = u.lo << n
|
||||
s.hi = u.hi << n | u.lo >> (64 - n)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// lsh returns u >> n
|
||||
pub fn (u Uint128) rsh(n u32) Uint128 {
|
||||
mut s := Uint128{}
|
||||
if n > 64 {
|
||||
s.hi = 0
|
||||
s.lo = u.hi << (n - 64)
|
||||
} else {
|
||||
s.lo = u.lo >> n | u.hi << (64 - n)
|
||||
s.hi = u.hi >> n
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// leading_zeros returns the number of leading zero bits in u; the result is 128
|
||||
// for u == 0.
|
||||
pub fn (u Uint128) leading_zeros() int {
|
||||
if u.hi > 0 {
|
||||
return bits.leading_zeros_64(u.hi)
|
||||
}
|
||||
return 64 + bits.leading_zeros_64(u.lo)
|
||||
}
|
||||
|
||||
// trailing_zeros returns the number of trailing zero bits in u; the result is
|
||||
// 128 for u == 0.
|
||||
pub fn (u Uint128) trailing_zeros() int {
|
||||
if u.lo > 0 {
|
||||
return bits.trailing_zeros_64(u.lo)
|
||||
}
|
||||
return 64 + bits.trailing_zeros_64(u.hi)
|
||||
}
|
||||
|
||||
// ones_count returns the number of one bits ("population count" in u)
|
||||
pub fn (u Uint128) ones_count() int {
|
||||
return bits.ones_count_64(u.hi) + bits.ones_count_64(u.lo)
|
||||
}
|
||||
|
||||
// rotate_left returns the value of u rotated left by (k mod 128) bits.
|
||||
pub fn (u Uint128) rotate_left(k int) Uint128 {
|
||||
n := u32(128)
|
||||
s := u32(k) & (n - 1)
|
||||
return u.lsh(s).or_(u.rsh(n - s))
|
||||
}
|
||||
|
||||
// rotate_right returns the value of u rotated right by (k mod 128) bits.
|
||||
pub fn (u Uint128) rotate_right(k int) Uint128 {
|
||||
return u.rotate_left(-k)
|
||||
}
|
||||
|
||||
// reverse returns the value of u with its bits in reversed order.
|
||||
pub fn (u Uint128) reverse() Uint128 {
|
||||
return Uint128{bits.reverse_64(u.hi), bits.reverse_64(u.lo)}
|
||||
}
|
||||
|
||||
// reverse_bytes returns the value of u with its bytes in reversed order.
|
||||
pub fn (u Uint128) reverse_bytes() Uint128 {
|
||||
return Uint128{bits.reverse_bytes_64(u.hi), bits.reverse_bytes_64(u.lo)}
|
||||
}
|
||||
|
||||
pub fn (u Uint128) not() Uint128 {
|
||||
return Uint128{~u.lo, ~u.hi}
|
||||
}
|
||||
|
||||
// len returns the minimum number of bits required to represent u; the result is
|
||||
// 0 for u == 0.
|
||||
pub fn (u Uint128) len() int {
|
||||
return 128 - u.leading_zeros()
|
||||
}
|
||||
|
||||
// string returns the base-10 representation of u as a string
|
||||
pub fn (u_ Uint128) str() string {
|
||||
mut u := u_
|
||||
if u.is_zero() {
|
||||
return '0'
|
||||
}
|
||||
|
||||
mut buf := '0000000000000000000000000000000000000000'.bytes() // log10(2^128) < 40
|
||||
|
||||
for i := buf.len; true; i -= 19 {
|
||||
q, mut r := u.quo_rem_64(u64(1e19))
|
||||
|
||||
mut n := int(0)
|
||||
for ; r != 0; r /= 10 {
|
||||
n++
|
||||
buf[i - n] += byte(r % 10)
|
||||
}
|
||||
if q.is_zero() {
|
||||
return buf[i - n..].bytestr()
|
||||
}
|
||||
u = q
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
// put_bytes stores u in b in little-endian order
|
||||
pub fn (u Uint128) put_bytes(mut b []byte) {
|
||||
binary.little_endian_put_u64(mut b, u.lo)
|
||||
binary.little_endian_put_u64(mut b, u.hi)
|
||||
}
|
||||
|
||||
// uint128_from_64 converts v to a Uint128 value
|
||||
pub fn uint128_from_64(v u64) Uint128 {
|
||||
return uint128_new(v, 0)
|
||||
}
|
||||
|
||||
pub fn uint128_new(lo u64, hi u64) Uint128 {
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
pub fn uint128_from_dec_str(value string) ?Uint128 {
|
||||
mut res := uint.uint128_zero
|
||||
for b_ in value.bytes() {
|
||||
b := b_ - '0'.bytes()[0]
|
||||
if b > 9 {
|
||||
return error('invalid character "$b"')
|
||||
}
|
||||
|
||||
r, overflow := res.overflowing_mul_64(10)
|
||||
|
||||
if overflow {
|
||||
return error('invalid length')
|
||||
}
|
||||
r2, overflow2 := r.overflowing_add_64(u64(b))
|
||||
|
||||
if overflow2 > 0 {
|
||||
return error('invalid length')
|
||||
}
|
||||
|
||||
res = r2
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (u Uint128) / (v Uint128) Uint128 {
|
||||
return u.div(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint128) % (v Uint128) Uint128 {
|
||||
return u.mod(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint128) + (v Uint128) Uint128 {
|
||||
return u.add(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint128) - (v Uint128) Uint128 {
|
||||
return u.sub(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint128) * (v Uint128) Uint128 {
|
||||
return u.mul(v)
|
||||
}
|
|
@ -0,0 +1,376 @@
|
|||
module uint
|
||||
|
||||
import math.bits
|
||||
|
||||
pub const (
|
||||
uint256_zero = Uint256{Uint128{}, Uint128{}}
|
||||
uint256_max = Uint256{uint128_max, uint128_max}
|
||||
)
|
||||
|
||||
// Uint256 is an unsigned 256-bit number
|
||||
pub struct Uint256 {
|
||||
pub mut:
|
||||
lo Uint128 = uint128_zero // lower 128 bit half
|
||||
hi Uint128 = uint128_zero // upper 128 bit half
|
||||
}
|
||||
|
||||
pub fn uint256_from_128(v Uint128) Uint256 {
|
||||
return Uint256{v, uint128_zero}
|
||||
}
|
||||
|
||||
pub fn uint256_from_64(v u64) Uint256 {
|
||||
return uint256_from_128(uint128_from_64(v))
|
||||
}
|
||||
|
||||
pub fn (u Uint256) is_zero() bool {
|
||||
return u.lo.is_zero() && u.hi.is_zero()
|
||||
}
|
||||
|
||||
pub fn (u Uint256) equals(v Uint256) bool {
|
||||
return u.lo.equals(v.lo) && u.hi.equals(v.hi)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) euqals_128(v Uint128) bool {
|
||||
return u.lo.equals(v) && u.hi.is_zero()
|
||||
}
|
||||
|
||||
pub fn (u Uint256) cmp(v Uint256) int {
|
||||
h := u.hi.cmp(v.hi)
|
||||
if h != 0 {
|
||||
return h
|
||||
}
|
||||
return u.lo.cmp(v.lo)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) cmp_128(v Uint128) int {
|
||||
if !u.hi.is_zero() {
|
||||
return 1
|
||||
}
|
||||
return u.lo.cmp(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) not() Uint256 {
|
||||
return Uint256{u.lo.not(), u.hi.not()}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) and(v Uint256) Uint256 {
|
||||
return Uint256{u.lo.and(v.lo), u.hi.and(v.hi)}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) and_128(v Uint128) Uint256 {
|
||||
return Uint256{u.lo.and(v), uint128_zero}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) or_(v Uint256) Uint256 {
|
||||
return Uint256{u.lo.or_(v.lo), u.hi.or_(v.hi)}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) or_128(v Uint128) Uint256 {
|
||||
return Uint256{u.lo.or_(v), u.hi}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) xor(v Uint256) Uint256 {
|
||||
return Uint256{u.lo.xor(v.lo), u.hi.xor(v.hi)}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) xor_128(v Uint128) Uint256 {
|
||||
return Uint256{u.lo.xor(v), u.hi}
|
||||
}
|
||||
|
||||
pub fn add_256(x Uint256, y Uint256, carry u64) (Uint256, u64) {
|
||||
mut sum := Uint256{}
|
||||
mut carry_out := u64(0)
|
||||
sum.lo, carry_out = add_128(x.lo, y.lo, carry)
|
||||
sum.hi, carry_out = add_128(x.hi, y.hi, carry_out)
|
||||
return sum, carry_out
|
||||
}
|
||||
|
||||
pub fn sub_256(x Uint256, y Uint256, borrow u64) (Uint256, u64) {
|
||||
mut diff := Uint256{}
|
||||
mut borrow_out := u64(0)
|
||||
diff.lo, borrow_out = sub_128(x.lo, y.lo, borrow)
|
||||
diff.hi, borrow_out = sub_128(x.hi, y.hi, borrow_out)
|
||||
return diff, borrow_out
|
||||
}
|
||||
|
||||
pub fn mul_256(x Uint256, y Uint256) (Uint256, Uint256) {
|
||||
mut hi := Uint256{}
|
||||
mut lo := Uint256{}
|
||||
|
||||
lo.hi, lo.lo = mul_128(x.lo, y.lo)
|
||||
hi.hi, hi.lo = mul_128(x.hi, y.hi)
|
||||
t0, t1 := mul_128(x.lo, y.hi)
|
||||
t2, t3 := mul_128(x.hi, y.lo)
|
||||
|
||||
mut c0 := u64(0)
|
||||
mut c1 := u64(0)
|
||||
|
||||
lo.hi, c0 = add_128(lo.hi, t1, 0)
|
||||
lo.hi, c1 = add_128(lo.hi, t3, 0)
|
||||
hi.lo, c0 = add_128(hi.lo, t0, c0)
|
||||
hi.lo, c1 = add_128(hi.lo, t2, c1)
|
||||
hi.hi = hi.hi.add_64(c0 + c1)
|
||||
|
||||
return hi, lo
|
||||
}
|
||||
|
||||
pub fn (u Uint256) add(v Uint256) Uint256 {
|
||||
sum, _ := add_256(u, v, 0)
|
||||
return sum
|
||||
}
|
||||
|
||||
pub fn (u Uint256) overflowing_add(v Uint256) (Uint256, u64) {
|
||||
sum, overflow := add_256(u, v, 0)
|
||||
return sum, overflow
|
||||
}
|
||||
|
||||
pub fn (u Uint256) add_128(v Uint128) Uint256 {
|
||||
lo, c0 := add_128(u.lo, v, 0)
|
||||
return Uint256{lo, u.hi.add_64(c0)}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) sub(v Uint256) Uint256 {
|
||||
diff, _ := sub_256(u, v, 0)
|
||||
return diff
|
||||
}
|
||||
|
||||
pub fn (u Uint256) sub_128(v Uint128) Uint256 {
|
||||
lo, b0 := sub_128(u.lo, v, 0)
|
||||
return Uint256{lo, u.hi.sub_64(b0)}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) mul(v Uint256) Uint256 {
|
||||
mut hi, mut lo := mul_128(u.lo, v.lo)
|
||||
hi = hi.add(u.hi.mul(v.lo))
|
||||
hi = hi.add(u.lo.mul(v.hi))
|
||||
return Uint256{lo, hi}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) mul_128(v Uint128) Uint256 {
|
||||
hi, lo := mul_128(u.lo, v)
|
||||
return Uint256{lo, hi.add(u.hi.mul(v))}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) quo_rem(v Uint256) (Uint256, Uint256) {
|
||||
if v.hi.is_zero() {
|
||||
q, r := u.quo_rem_128(v.lo)
|
||||
return q, uint256_from_128(r)
|
||||
}
|
||||
|
||||
n := u64(v.hi.leading_zeros())
|
||||
u1, v1 := u.rsh(1), v.lsh(u32(n))
|
||||
mut tq, _ := div_128(u1.hi, u1.lo, v1.hi)
|
||||
tq = tq.rsh(u32(127 - n))
|
||||
if !tq.is_zero() {
|
||||
tq = tq.sub_64(1)
|
||||
}
|
||||
|
||||
mut q, mut r := uint256_from_128(tq), u.sub(v.mul_128(tq))
|
||||
if r.cmp(v) >= 0 {
|
||||
q = q.add_128(Uint128{1, 0})
|
||||
r = r.sub(v)
|
||||
}
|
||||
return q, r
|
||||
}
|
||||
|
||||
pub fn (u Uint256) quo_rem_128(v Uint128) (Uint256, Uint128) {
|
||||
if u.hi.cmp(v) < 0 {
|
||||
lo, r := div_128(u.hi, u.lo, v)
|
||||
return Uint256{lo, uint128_zero}, r
|
||||
}
|
||||
|
||||
hi, r := div_128(uint128_zero, u.hi, v)
|
||||
lo, r2 := div_128(r, u.lo, v)
|
||||
return Uint256{lo, hi}, r2
|
||||
}
|
||||
|
||||
pub fn (u Uint256) quo_rem_64(v u64) (Uint256, u64) {
|
||||
mut q := Uint256{}
|
||||
mut r := u64(0)
|
||||
q.lo.hi, r = bits.div_64(r, u.lo.hi, v)
|
||||
q.lo.lo, r = bits.div_64(r, u.lo.lo, v)
|
||||
return q, r
|
||||
}
|
||||
|
||||
pub fn (u Uint256) rsh(n_ u32) Uint256 {
|
||||
mut n := n_
|
||||
if n > 128 {
|
||||
return Uint256{u.hi.rsh(n - 128), uint128_zero}
|
||||
}
|
||||
|
||||
if n > 64 {
|
||||
n -= 64
|
||||
return Uint256{Uint128{u.lo.hi >> n | u.hi.lo << (64 - n), u.hi.lo >> n | u.hi.hi << (64 - n)}, Uint128{u.hi.hi >> n, 0}}
|
||||
}
|
||||
return Uint256{Uint128{u.lo.lo >> n | u.lo.hi << (64 - n), u.lo.hi >> n | u.hi.lo << (64 - n)}, Uint128{u.hi.lo >> n | u.hi.hi << (64 - n), u.hi.hi >> n}}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) lsh(n_ u32) Uint256 {
|
||||
mut n := n_
|
||||
if n > 128 {
|
||||
return Uint256{u.lo.lsh(n - 128), uint128_zero}
|
||||
}
|
||||
|
||||
if n > 64 {
|
||||
n -= 64
|
||||
return Uint256{Uint128{u.lo.lo << n, 0}, Uint128{u.lo.hi << n | u.lo.lo >> (64 - n), u.hi.lo << n | u.lo.hi >> (64 - n)}}
|
||||
}
|
||||
|
||||
return Uint256{Uint128{u.lo.lo << 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)}}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) div(v Uint256) Uint256 {
|
||||
q, _ := u.quo_rem(v)
|
||||
return q
|
||||
}
|
||||
|
||||
pub fn (u Uint256) div_128(v Uint128) Uint256 {
|
||||
q, _ := u.quo_rem_128(v)
|
||||
return q
|
||||
}
|
||||
|
||||
pub fn (u Uint256) div_64(v u64) Uint256 {
|
||||
q, _ := u.quo_rem_64(v)
|
||||
return q
|
||||
}
|
||||
|
||||
pub fn (u Uint256) mod(v Uint256) Uint256 {
|
||||
_, r := u.quo_rem(v)
|
||||
return r
|
||||
}
|
||||
|
||||
pub fn (u Uint256) mod_128(v Uint128) Uint128 {
|
||||
_, r := u.quo_rem_128(v)
|
||||
return r
|
||||
}
|
||||
|
||||
pub fn (u Uint256) mod_64(v u64) u64 {
|
||||
_, r := u.quo_rem_64(v)
|
||||
return r
|
||||
}
|
||||
|
||||
pub fn (u Uint256) rotate_left(k int) Uint256 {
|
||||
mut n := u32(k) & 255
|
||||
if n < 64 {
|
||||
if n == 0 {
|
||||
return u
|
||||
}
|
||||
|
||||
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)}}
|
||||
}
|
||||
n -= 64
|
||||
if n < 64 {
|
||||
if n == 0 {
|
||||
return Uint256{Uint128{u.hi.hi, u.lo.lo}, Uint128{u.lo.hi, u.hi.lo}}
|
||||
}
|
||||
|
||||
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)}}
|
||||
}
|
||||
|
||||
n -= 64
|
||||
if n < 64 {
|
||||
if n == 0 {
|
||||
return Uint256{u.hi, u.lo}
|
||||
}
|
||||
|
||||
return Uint256{Uint128{u.hi.lo << n | u.lo.hi >> (64 - n), u.hi.hi << n | u.hi.lo >> (64 - n)}, Uint128{}}
|
||||
}
|
||||
n -= 64
|
||||
if n == 0 {
|
||||
return Uint256{Uint128{u.lo.hi, u.hi.lo}, Uint128{u.hi.hi, u.lo.lo}}
|
||||
}
|
||||
|
||||
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)}}
|
||||
}
|
||||
|
||||
pub fn (u Uint256) rotate_right(k int) Uint256 {
|
||||
return u.rotate_left(-k)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) len() int {
|
||||
if !u.hi.is_zero() {
|
||||
return 128 + u.hi.len()
|
||||
}
|
||||
return u.lo.len()
|
||||
}
|
||||
|
||||
pub fn (u Uint256) leading_zeros() int {
|
||||
if !u.hi.is_zero() {
|
||||
return u.hi.leading_zeros()
|
||||
}
|
||||
return 128 + u.lo.leading_zeros()
|
||||
}
|
||||
|
||||
pub fn (u Uint256) trailing_zeros() int {
|
||||
if !u.lo.is_zero() {
|
||||
return u.lo.trailing_zeros()
|
||||
}
|
||||
|
||||
return 128 + u.hi.trailing_zeros()
|
||||
}
|
||||
|
||||
pub fn (u Uint256) ones_count() int {
|
||||
return u.lo.ones_count() + u.hi.ones_count()
|
||||
}
|
||||
|
||||
pub fn (u_ Uint256) str() string {
|
||||
mut u := u_
|
||||
if u.hi.is_zero() {
|
||||
if u.lo.is_zero() {
|
||||
return '0'
|
||||
}
|
||||
return u.lo.str()
|
||||
}
|
||||
|
||||
mut buf := '000000000000000000000000000000000000000000000000000000000000000000000000000000'.bytes()
|
||||
|
||||
for i := buf.len; true; i -= 19 {
|
||||
q, mut r := u.quo_rem_64(u64(1e19))
|
||||
mut n := 0
|
||||
for ; r != 0; r /= 10 {
|
||||
n++
|
||||
buf[i - n] += byte(r % 10)
|
||||
}
|
||||
if q.is_zero() {
|
||||
return buf[i - n..].bytestr()
|
||||
}
|
||||
u = q
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn uint256_from_dec_str(value string) ?Uint256 {
|
||||
mut res := uint.uint256_zero
|
||||
for b_ in value.bytes() {
|
||||
b := b_ - '0'.bytes()[0]
|
||||
if b > 9 {
|
||||
return error('invalid character "$b"')
|
||||
}
|
||||
|
||||
r := res.mul_128(uint128_from_64(10))
|
||||
|
||||
r2 := r.add_128(uint128_from_64(u64(b)))
|
||||
res = r2
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
pub fn (u Uint256) / (v Uint256) Uint256 {
|
||||
return u.div(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) % (v Uint256) Uint256 {
|
||||
return u.mod(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) + (v Uint256) Uint256 {
|
||||
return u.add(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) - (v Uint256) Uint256 {
|
||||
return u.sub(v)
|
||||
}
|
||||
|
||||
pub fn (u Uint256) * (v Uint256) Uint256 {
|
||||
return u.mul(v)
|
||||
}
|
Loading…
Reference in New Issue