Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,491 @@
|
||||
module unsigned
|
||||
|
||||
import math.bits
|
||||
import encoding.binary
|
||||
|
||||
pub struct Uint128 {
|
||||
pub mut:
|
||||
lo u64
|
||||
hi u64
|
||||
}
|
||||
|
||||
pub const uint128_zero = Uint128{}
|
||||
pub const 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 returns 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}
|
||||
}
|
||||
|
||||
// add_128 return u + v and the carry
|
||||
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
|
||||
}
|
||||
|
||||
// sub_128 returns u - v and the borrow
|
||||
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
|
||||
}
|
||||
|
||||
// mul_128 returns u x v
|
||||
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
|
||||
}
|
||||
|
||||
// div_128 returns u / v
|
||||
pub fn div_128(a_hi Uint128, a_lo Uint128, b Uint128) (Uint128, Uint128) {
|
||||
a := uint256_new(a_lo, a_hi)
|
||||
b_256 := uint256_new(b, uint128_zero)
|
||||
if a < b_256 {
|
||||
return uint128_zero, a_lo
|
||||
}
|
||||
if b.is_zero() {
|
||||
panic('Division by zero')
|
||||
}
|
||||
if a.hi.is_zero() {
|
||||
return a.lo.quo_rem(b)
|
||||
}
|
||||
shift := u32(b_256.leading_zeros() - a.leading_zeros())
|
||||
mut af := a
|
||||
mut bf := b_256.lsh(shift)
|
||||
mut quotient := uint128_zero
|
||||
|
||||
for _ in 0 .. shift + 1 {
|
||||
quotient = quotient.lsh(1)
|
||||
diff_result := bf.add(af.not())
|
||||
s := u64(i64(diff_result.hi.hi) >> 63)
|
||||
quotient.lo |= s & 1
|
||||
mask := uint256_new(uint128_new(s, s), uint128_new(s, s))
|
||||
af = af.sub(bf.and(mask))
|
||||
bf = bf.rsh(1)
|
||||
}
|
||||
return quotient, af.lo
|
||||
}
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
// overflowing_mul_64 returns u x v even if result size > 128
|
||||
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
|
||||
}
|
||||
|
||||
// overflowing_add_64 returns u + v even if result size > 128
|
||||
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 (a Uint128) quo_rem(b Uint128) (Uint128, Uint128) {
|
||||
if a < b {
|
||||
return uint128_zero, a
|
||||
}
|
||||
if b.is_zero() {
|
||||
panic('Division by zero')
|
||||
}
|
||||
if b.hi == 0 {
|
||||
quotient, remainder := a.quo_rem_64(b.lo)
|
||||
return quotient, uint128_from_64(remainder)
|
||||
}
|
||||
shift := u32(b.leading_zeros() - a.leading_zeros())
|
||||
mut af := a
|
||||
mut bf := b.lsh(shift)
|
||||
mut quotient := uint128_zero
|
||||
|
||||
for _ in 0 .. shift + 1 {
|
||||
quotient = quotient.lsh(1)
|
||||
diff_result := bf.add(af.not())
|
||||
s := u64(i64(diff_result.hi) >> 63)
|
||||
quotient.lo |= s & 1
|
||||
mask := uint128_new(s, s)
|
||||
af = af.sub(bf.and(mask))
|
||||
bf = bf.rsh(1)
|
||||
}
|
||||
return quotient, af
|
||||
}
|
||||
|
||||
// lsh returns u << n
|
||||
pub fn (u Uint128) lsh(n u32) Uint128 {
|
||||
mut s := Uint128{}
|
||||
if n == 0 {
|
||||
s.lo = u.lo
|
||||
s.hi = u.hi
|
||||
} else if n >= 128 {
|
||||
s.lo = 0
|
||||
s.hi = 0
|
||||
} else if n == 64 {
|
||||
s.lo = 0
|
||||
s.hi = u.lo
|
||||
} else 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
|
||||
}
|
||||
|
||||
// rsh returns u >> n
|
||||
pub fn (u Uint128) rsh(n u32) Uint128 {
|
||||
mut s := Uint128{}
|
||||
if n == 0 {
|
||||
s.lo = u.lo
|
||||
s.hi = u.hi
|
||||
} else if n >= 128 {
|
||||
s.lo = 0
|
||||
s.hi = 0
|
||||
} else if n == 64 {
|
||||
s.hi = 0
|
||||
s.lo = u.hi
|
||||
} else 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)}
|
||||
}
|
||||
|
||||
// not returns a binary negation of the Uint128 value
|
||||
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] += u8(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 []u8) {
|
||||
binary.little_endian_put_u64(mut b[..8], u.lo)
|
||||
binary.little_endian_put_u64(mut b[8..], u.hi)
|
||||
}
|
||||
|
||||
// uint128_from_64 converts v to a Uint128 value
|
||||
pub fn uint128_from_64(v u64) Uint128 {
|
||||
return uint128_new(v, 0)
|
||||
}
|
||||
|
||||
// uint128_new creates new Uint128 with given `lo` and `hi`
|
||||
pub fn uint128_new(lo u64, hi u64) Uint128 {
|
||||
return Uint128{lo, hi}
|
||||
}
|
||||
|
||||
// unint_from_dec_str returns an error or new Uint128 from given string.
|
||||
// The `_` character is allowed as a separator.
|
||||
pub fn uint128_from_dec_str(value string) !Uint128 {
|
||||
mut res := uint128_zero
|
||||
underscore := `_`
|
||||
|
||||
for b_ in value {
|
||||
b := b_ - `0`
|
||||
if b > 9 {
|
||||
// allow _ as a separator in decimal strings
|
||||
if b_ == underscore {
|
||||
continue
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// / -> returns u / v
|
||||
pub fn (u Uint128) / (v Uint128) Uint128 {
|
||||
return u.div(v)
|
||||
}
|
||||
|
||||
// % -> returns u % v
|
||||
pub fn (u Uint128) % (v Uint128) Uint128 {
|
||||
return u.mod(v)
|
||||
}
|
||||
|
||||
// + -> returns u + v
|
||||
pub fn (u Uint128) + (v Uint128) Uint128 {
|
||||
return u.add(v)
|
||||
}
|
||||
|
||||
// - -> returns u - v
|
||||
pub fn (u Uint128) - (v Uint128) Uint128 {
|
||||
return u.sub(v)
|
||||
}
|
||||
|
||||
// * -> returns u * v
|
||||
pub fn (u Uint128) * (v Uint128) Uint128 {
|
||||
return u.mul(v)
|
||||
}
|
||||
|
||||
// < -> returns true if u < v
|
||||
pub fn (u Uint128) < (v Uint128) bool {
|
||||
return u.cmp(v) == -1
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
import math.big
|
||||
import math.unsigned
|
||||
import rand
|
||||
|
||||
fn test_str() {
|
||||
x := unsigned.uint128_from_dec_str('170141183460469231713240559642174554112') or { panic('') }
|
||||
assert x.str() == '170141183460469231713240559642174554112'
|
||||
y := unsigned.uint128_from_64(42)
|
||||
assert y.str() == '42'
|
||||
}
|
||||
|
||||
fn test_ops() {
|
||||
x := unsigned.uint128_from_64(18446744073709551615)
|
||||
y := unsigned.uint128_from_64(18446744073709551615)
|
||||
z := unsigned.uint128_from_dec_str('340282366920938463426481119284349108225') or {
|
||||
assert false
|
||||
panic('')
|
||||
}
|
||||
assert (x * y).str() == '340282366920938463426481119284349108225'
|
||||
assert (x + y).str() == '36893488147419103230'
|
||||
assert (z / unsigned.uint128_from_64(2)).str() == '170141183460469231713240559642174554112'
|
||||
assert (unsigned.uint128_from_dec_str('170141183460469231713240559642174554112') or {
|
||||
panic('')
|
||||
} - unsigned.uint128_from_64(2)).str() == '170141183460469231713240559642174554110'
|
||||
|
||||
assert x == y
|
||||
assert unsigned.uint128_from_dec_str('340282366920938463426481119284349108225') or {
|
||||
assert false
|
||||
panic('')
|
||||
} > y
|
||||
}
|
||||
|
||||
struct LeadingZeros {
|
||||
l unsigned.Uint128
|
||||
r unsigned.Uint128
|
||||
zeros int
|
||||
}
|
||||
|
||||
fn new(x u64, y u64) unsigned.Uint128 {
|
||||
return unsigned.Uint128{x, y}
|
||||
}
|
||||
|
||||
fn test_leading_zeros() {
|
||||
tcs := [
|
||||
LeadingZeros{
|
||||
l: new(0x00, 0xf000000000000000)
|
||||
r: new(0x00, 0x8000000000000000)
|
||||
zeros: 1
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0x00, 0xf000000000000000)
|
||||
r: new(0x00, 0xc000000000000000)
|
||||
zeros: 2
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0x00, 0xf000000000000000)
|
||||
r: new(0x00, 0xe000000000000000)
|
||||
zeros: 3
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0x00, 0xffff000000000000)
|
||||
r: new(0x00, 0xff00000000000000)
|
||||
zeros: 8
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0x00, 0x000000000000ffff)
|
||||
r: new(0x00, 0x000000000000ff00)
|
||||
zeros: 56
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0xf000000000000000, 0x01)
|
||||
r: new(0x4000000000000000, 0x00)
|
||||
zeros: 63
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0xf000000000000000, 0x00)
|
||||
r: new(0x4000000000000000, 0x00)
|
||||
zeros: 64
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0xf000000000000000, 0x00)
|
||||
r: new(0x8000000000000000, 0x00)
|
||||
zeros: 65
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0x00, 0x00)
|
||||
r: new(0x00, 0x00)
|
||||
zeros: 128
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(0x01, 0x00)
|
||||
r: new(0x00, 0x00)
|
||||
zeros: 127
|
||||
},
|
||||
]
|
||||
|
||||
for tc in tcs {
|
||||
zeros := tc.l.xor(tc.r).leading_zeros()
|
||||
assert zeros == tc.zeros
|
||||
}
|
||||
}
|
||||
|
||||
fn test_separators() {
|
||||
// numbers of varying lengths and a random
|
||||
// scattering of '_' throughout.
|
||||
test_strings := [
|
||||
'_',
|
||||
'__',
|
||||
'_0',
|
||||
'0_',
|
||||
'_0_',
|
||||
'_1',
|
||||
'1_',
|
||||
'_1_',
|
||||
'1_2',
|
||||
'_12',
|
||||
'12_',
|
||||
'12_3',
|
||||
'1_23_4',
|
||||
'12_345',
|
||||
'_123_456_',
|
||||
'1_234_567',
|
||||
'1234_5678',
|
||||
'_123456789',
|
||||
'1234567890_',
|
||||
'0_123_456_789_0',
|
||||
'90_12_345_67890',
|
||||
'8901_234_567890_',
|
||||
'_7890_123456789_0',
|
||||
'678901234_567890',
|
||||
'567890_1234567890',
|
||||
'4567890123__4567890',
|
||||
'_34567890123_4567890',
|
||||
'2345678_90123_4567890',
|
||||
'123456789_01_234567890',
|
||||
'01234567_8901234567890',
|
||||
'9012345678901_234567890__',
|
||||
'8_90123456_78901234567890',
|
||||
'78901234567890_123_4567890',
|
||||
'___67890123_4_5_6_78901234567890___',
|
||||
'567890123_45678901234567890',
|
||||
'45_67890123456789_01234567890',
|
||||
'3456789012_345678901234567890',
|
||||
'234_567890_1234_5__67890_1234567890_',
|
||||
'12345678_90123_456789_0123_4567890',
|
||||
'0_123_456_789_012_345_678_901_234_567_890',
|
||||
'90_123456__78901__234567_8901_234567890',
|
||||
'890123456789012345678901234567_890',
|
||||
'7890_1234567_8901234567890_1234567890',
|
||||
'67890123_45678_901234567_8901234567890',
|
||||
'567890_1234567890_12345678901_234567890',
|
||||
'45678_9012345_6789012345678901234567890_',
|
||||
'34567890123456_789012345678901234567890',
|
||||
'234567_890_1234567890_1234567890_1234567890',
|
||||
'334567890_1234567890_1234567890_1234567890',
|
||||
'340282360_0000000000_0000000000_0000000000',
|
||||
'340282366_9209384634_2648111928_4349108225',
|
||||
'340282366_9209384634_6337460743_1768211455',
|
||||
]
|
||||
|
||||
for ts in test_strings {
|
||||
with := unsigned.uint128_from_dec_str(ts) or {
|
||||
assert false, 'invalid Uint128 string ${ts}'
|
||||
panic('')
|
||||
}
|
||||
|
||||
without := unsigned.uint128_from_dec_str(ts.replace('_', '')) or {
|
||||
assert false, 'invalid Uint128 string ${ts.replace('_', '')}'
|
||||
panic('')
|
||||
}
|
||||
|
||||
assert with == without
|
||||
}
|
||||
}
|
||||
|
||||
fn test_new() {
|
||||
assert unsigned.uint128_new(max_u64, max_u64) == unsigned.uint128_max
|
||||
}
|
||||
|
||||
fn test_lsh() {
|
||||
a := unsigned.uint128_from_dec_str('123456789012345678901234567890')!
|
||||
assert a.str() == a.lsh(0).str()
|
||||
assert '246913578024691357802469135780' == a.lsh(1).str()
|
||||
assert '259801135457060040952792416454273138688' == a.lsh(64).str()
|
||||
assert '302984417681386893975453667670529933312' == a.lsh(100).str()
|
||||
assert unsigned.uint128_zero == a.lsh(200)
|
||||
}
|
||||
|
||||
fn test_rsh() {
|
||||
a := unsigned.uint128_from_dec_str('279625844435276397900870454226348864638')!
|
||||
assert a.str() == a.rsh(0).str()
|
||||
assert '139812922217638198950435227113174432319' == a.rsh(1).str()
|
||||
assert '15158547400991018568' == a.rsh(64).str()
|
||||
assert '220585896' == a.rsh(100).str()
|
||||
assert '1' == a.rsh(127).str()
|
||||
assert unsigned.uint128_zero == a.rsh(200)
|
||||
}
|
||||
|
||||
fn test_quo_rem() {
|
||||
for a_lo in 0 .. 16 {
|
||||
for a_hi in 0 .. 16 {
|
||||
for b_lo in 0 .. 16 {
|
||||
for b_hi in 0 .. 16 {
|
||||
a := unsigned.uint128_new(u64(1 << a_lo), u64(1 << a_hi))
|
||||
b := unsigned.uint128_new(u64(1 << b_lo), u64(1 << b_hi))
|
||||
big_a := big.integer_from_string(a.str())!
|
||||
big_b := big.integer_from_string(b.str())!
|
||||
q, r := a.quo_rem(b)
|
||||
big_q, big_r := big_a.div_mod(big_b)
|
||||
assert q.str() == big_q.str()
|
||||
assert r.str() == big_r.str()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_div_128() {
|
||||
for a_lo in 0 .. 4 {
|
||||
for a_hi in 0 .. 4 {
|
||||
for b_lo in 0 .. 4 {
|
||||
for b_hi in 0 .. 4 {
|
||||
for c_lo in 0 .. 4 {
|
||||
for c_hi in 0 .. 4 {
|
||||
a := unsigned.uint128_new(u64(1 << a_lo), u64(1 << a_hi))
|
||||
b := unsigned.uint128_new(u64(1 << b_lo), u64(1 << b_hi))
|
||||
c := unsigned.uint128_new(u64(1 << c_lo), u64(1 << c_hi))
|
||||
if c.cmp(a) <= 0 {
|
||||
continue
|
||||
}
|
||||
aa := unsigned.uint256_new(b, a)
|
||||
big_a := big.integer_from_string(aa.str())!
|
||||
big_b := big.integer_from_string(c.str())!
|
||||
q, r := unsigned.div_128(a, b, c)
|
||||
big_q, big_r := big_a.div_mod(big_b)
|
||||
assert q.str() == big_q.str()
|
||||
assert r.str() == big_r.str()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_put_bytes() {
|
||||
a := unsigned.uint128_new(rand.u64(), rand.u64())
|
||||
b := a.reverse_bytes()
|
||||
mut buf_a := []u8{len: 16}
|
||||
mut buf_b := []u8{len: 16}
|
||||
a.put_bytes(mut buf_a)
|
||||
b.put_bytes(mut buf_b)
|
||||
assert buf_a == buf_b.reverse()
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
module unsigned
|
||||
|
||||
import math.bits
|
||||
|
||||
pub const uint256_zero = Uint256{Uint128{}, Uint128{}}
|
||||
pub const 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
|
||||
}
|
||||
|
||||
// uint256_from_128 creates a new `unsigned.Uint256` from the given Uint128 value
|
||||
pub fn uint256_from_128(v Uint128) Uint256 {
|
||||
return Uint256{v, uint128_zero}
|
||||
}
|
||||
|
||||
// uint256_from_64 creates a new `unsigned.Uint256` from the given u64 value
|
||||
pub fn uint256_from_64(v u64) Uint256 {
|
||||
return uint256_from_128(uint128_from_64(v))
|
||||
}
|
||||
|
||||
// uint256_new creates new Uint256 with given `lo` and `hi`
|
||||
pub fn uint256_new(lo Uint128, hi Uint128) Uint256 {
|
||||
return Uint256{lo, hi}
|
||||
}
|
||||
|
||||
// is_zero checks if specified Uint256 is zero
|
||||
pub fn (u Uint256) is_zero() bool {
|
||||
return u.lo.is_zero() && u.hi.is_zero()
|
||||
}
|
||||
|
||||
// equals checks if the two Uint256 values match one another
|
||||
pub fn (u Uint256) equals(v Uint256) bool {
|
||||
return u.lo.equals(v.lo) && u.hi.equals(v.hi)
|
||||
}
|
||||
|
||||
// equals_128 checks if the Uint256 value matches the Uint128 value
|
||||
pub fn (u Uint256) equals_128(v Uint128) bool {
|
||||
return u.lo.equals(v) && u.hi.is_zero()
|
||||
}
|
||||
|
||||
// cmp returns 1 if u is greater than v, -1 if u is less than v, or 0 if equal
|
||||
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)
|
||||
}
|
||||
|
||||
// cmp_128 returns 1 if u is greater than v (Uint128), -1 if u is less than v, or 0 if equal
|
||||
pub fn (u Uint256) cmp_128(v Uint128) int {
|
||||
if !u.hi.is_zero() {
|
||||
return 1
|
||||
}
|
||||
return u.lo.cmp(v)
|
||||
}
|
||||
|
||||
// not returns a binary negation of the Uint256 value
|
||||
pub fn (u Uint256) not() Uint256 {
|
||||
return Uint256{u.lo.not(), u.hi.not()}
|
||||
}
|
||||
|
||||
// and returns a Uint256 value that is the bitwise and of u and v
|
||||
pub fn (u Uint256) and(v Uint256) Uint256 {
|
||||
return Uint256{u.lo.and(v.lo), u.hi.and(v.hi)}
|
||||
}
|
||||
|
||||
// and_128 returns a Uint256 value that is the bitwise and of u and v, which is a Uint128
|
||||
pub fn (u Uint256) and_128(v Uint128) Uint256 {
|
||||
return Uint256{u.lo.and(v), uint128_zero}
|
||||
}
|
||||
|
||||
// or_ returns a Uint256 value that is the bitwise or of u and v
|
||||
pub fn (u Uint256) or_(v Uint256) Uint256 {
|
||||
return Uint256{u.lo.or_(v.lo), u.hi.or_(v.hi)}
|
||||
}
|
||||
|
||||
// or_128 returns a Uint256 value that is the bitwise or of u and v, which is a Uint128
|
||||
pub fn (u Uint256) or_128(v Uint128) Uint256 {
|
||||
return Uint256{u.lo.or_(v), u.hi}
|
||||
}
|
||||
|
||||
// xor returns a Uint256 value that is the bitwise xor of u and v
|
||||
pub fn (u Uint256) xor(v Uint256) Uint256 {
|
||||
return Uint256{u.lo.xor(v.lo), u.hi.xor(v.hi)}
|
||||
}
|
||||
|
||||
// xor_128 returns a Uint256 value that is the bitwise xor of u and v, which is a Uint128
|
||||
pub fn (u Uint256) xor_128(v Uint128) Uint256 {
|
||||
return Uint256{u.lo.xor(v), u.hi}
|
||||
}
|
||||
|
||||
// add_256 return u + v and the carry
|
||||
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
|
||||
}
|
||||
|
||||
// sub_256 returns u - v and the borrow
|
||||
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
|
||||
}
|
||||
|
||||
// mul_256 returns u x v
|
||||
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
|
||||
}
|
||||
|
||||
// add returns a Uint256 that is equal to u+v
|
||||
pub fn (u Uint256) add(v Uint256) Uint256 {
|
||||
sum, _ := add_256(u, v, 0)
|
||||
return sum
|
||||
}
|
||||
|
||||
// overflowing_add returns u + v even if result size > 256
|
||||
pub fn (u Uint256) overflowing_add(v Uint256) (Uint256, u64) {
|
||||
sum, overflow := add_256(u, v, 0)
|
||||
return sum, overflow
|
||||
}
|
||||
|
||||
// add_128 returns a Uint256 that is equal to u+v, v being a Uint128
|
||||
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)}
|
||||
}
|
||||
|
||||
// sub returns a Uint256 that is equal to u-v
|
||||
pub fn (u Uint256) sub(v Uint256) Uint256 {
|
||||
diff, _ := sub_256(u, v, 0)
|
||||
return diff
|
||||
}
|
||||
|
||||
// sub_128 returns a Uint256 that is equal to u-v, v being a Uint128
|
||||
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)}
|
||||
}
|
||||
|
||||
// mul returns a Uint256 that is eqal to u*v
|
||||
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}
|
||||
}
|
||||
|
||||
// mul_128 returns a Uint256 that is eqal to u*v, v being a Uint128
|
||||
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))}
|
||||
}
|
||||
|
||||
// quo_rem returns q = u/v and r = u%v
|
||||
pub fn (u Uint256) quo_rem(v Uint256) (Uint256, Uint256) {
|
||||
if v.hi.is_zero() && v.lo.hi == 0 {
|
||||
q, r := u.quo_rem_64(v.lo.lo)
|
||||
return q, uint256_from_64(r)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// quo_rem_128 returns q = u/v and r = u%v
|
||||
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
|
||||
}
|
||||
|
||||
// quo_rem_64 returns q = u/v and r = u%v
|
||||
pub fn (u Uint256) quo_rem_64(v u64) (Uint256, u64) {
|
||||
mut q := Uint256{}
|
||||
mut r := u64(0)
|
||||
q.hi.hi, r = bits.div_64(r, u.hi.hi, v)
|
||||
q.hi.lo, r = bits.div_64(r, u.hi.lo, v)
|
||||
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
|
||||
}
|
||||
|
||||
// rsh returns a new Uint256 that has been right bit shifted
|
||||
pub fn (u Uint256) rsh(n u32) Uint256 {
|
||||
mut s := Uint256{}
|
||||
if n == 0 {
|
||||
s.lo = u.lo
|
||||
s.hi = u.hi
|
||||
} else if n >= 256 {
|
||||
s.lo = uint128_zero
|
||||
s.hi = uint128_zero
|
||||
} else if n == 128 {
|
||||
s.hi = uint128_zero
|
||||
s.lo = u.hi
|
||||
} else if n > 128 {
|
||||
s.hi = uint128_zero
|
||||
s.lo = u.hi.rsh(n - 128)
|
||||
} else if n == 64 {
|
||||
s.lo = Uint128{u.lo.hi, u.hi.lo}
|
||||
s.hi = Uint128{u.hi.hi, 0}
|
||||
} else if n > 64 {
|
||||
shift := n - 64
|
||||
s.lo =
|
||||
Uint128{u.lo.hi >> shift | u.hi.lo << (64 - shift), u.hi.lo >> shift | u.hi.hi << (64 - shift)}
|
||||
s.hi = Uint128{u.hi.hi >> shift, 0}
|
||||
} else {
|
||||
s.lo = Uint128{u.lo.lo >> n | u.lo.hi << (64 - n), u.lo.hi >> n | u.hi.lo << (64 - n)}
|
||||
s.hi = Uint128{u.hi.lo >> n | u.hi.hi << (64 - n), u.hi.hi >> n}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// lsh returns a new Uint256 that has been left bit shifted
|
||||
pub fn (u Uint256) lsh(n u32) Uint256 {
|
||||
mut s := Uint256{}
|
||||
if n == 0 {
|
||||
s.lo = u.lo
|
||||
s.hi = u.hi
|
||||
} else if n >= 256 {
|
||||
s.lo = uint128_zero
|
||||
s.hi = uint128_zero
|
||||
} else if n == 128 {
|
||||
s.lo = uint128_zero
|
||||
s.hi = u.lo
|
||||
} else if n > 128 {
|
||||
s.lo = uint128_zero
|
||||
s.hi = u.lo.lsh(n - 128)
|
||||
} else if n == 64 {
|
||||
s.lo = Uint128{0, u.lo.lo}
|
||||
s.hi = Uint128{u.lo.hi, u.hi.lo}
|
||||
} else if n > 64 {
|
||||
shift := n - 64
|
||||
s.lo = Uint128{0, u.lo.lo << shift}
|
||||
s.hi =
|
||||
Uint128{u.lo.lo >> (64 - shift) | u.lo.hi << shift, u.lo.hi >> (64 - shift) | u.hi.lo << shift}
|
||||
} else {
|
||||
s.lo = Uint128{u.lo.lo << n, u.lo.hi << n | u.lo.lo >> (64 - n)}
|
||||
s.hi = Uint128{u.hi.lo << n | u.lo.hi >> (64 - n), u.hi.hi << n | u.hi.lo >> (64 - n)}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// div returns u / v
|
||||
pub fn (u Uint256) div(v Uint256) Uint256 {
|
||||
q, _ := u.quo_rem(v)
|
||||
return q
|
||||
}
|
||||
|
||||
// div_128 returns u / v
|
||||
pub fn (u Uint256) div_128(v Uint128) Uint256 {
|
||||
q, _ := u.quo_rem_128(v)
|
||||
return q
|
||||
}
|
||||
|
||||
// div_64 returns u / v
|
||||
pub fn (u Uint256) div_64(v u64) Uint256 {
|
||||
q, _ := u.quo_rem_64(v)
|
||||
return q
|
||||
}
|
||||
|
||||
// mod returns r = u % v
|
||||
pub fn (u Uint256) mod(v Uint256) Uint256 {
|
||||
_, r := u.quo_rem(v)
|
||||
return r
|
||||
}
|
||||
|
||||
// mod_128 returns r = u % v
|
||||
pub fn (u Uint256) mod_128(v Uint128) Uint128 {
|
||||
_, r := u.quo_rem_128(v)
|
||||
return r
|
||||
}
|
||||
|
||||
// mod_64 returns r = u % v
|
||||
pub fn (u Uint256) mod_64(v u64) u64 {
|
||||
_, r := u.quo_rem_64(v)
|
||||
return r
|
||||
}
|
||||
|
||||
// rotate_left returns a new Uint256 that has been left bit shifted
|
||||
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{u.lo.lo << n | u.hi.hi >> (64 - n), u.lo.hi << n | u.lo.lo >> (64 - n)}}
|
||||
}
|
||||
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)}}
|
||||
}
|
||||
|
||||
// rotate_right returns a new Uint256 that has been right bit shifted
|
||||
pub fn (u Uint256) rotate_right(k int) Uint256 {
|
||||
return u.rotate_left(-k)
|
||||
}
|
||||
|
||||
// len returns the length of the binary value without the leading zeros
|
||||
pub fn (u Uint256) len() int {
|
||||
if !u.hi.is_zero() {
|
||||
return 128 + u.hi.len()
|
||||
}
|
||||
return u.lo.len()
|
||||
}
|
||||
|
||||
// leading_zeros returns the number of 0s at the beginning of the binary value of the Uint256 value [0, 256]
|
||||
pub fn (u Uint256) leading_zeros() int {
|
||||
if !u.hi.is_zero() {
|
||||
return u.hi.leading_zeros()
|
||||
}
|
||||
return 128 + u.lo.leading_zeros()
|
||||
}
|
||||
|
||||
// trailing_zeros returns the number of 0s at the end of the binary value of the Uint256 value [0,256]
|
||||
pub fn (u Uint256) trailing_zeros() int {
|
||||
if !u.lo.is_zero() {
|
||||
return u.lo.trailing_zeros()
|
||||
}
|
||||
|
||||
return 128 + u.hi.trailing_zeros()
|
||||
}
|
||||
|
||||
// ones_count returns the number of ones in the binary value of the Uint256 value
|
||||
pub fn (u Uint256) ones_count() int {
|
||||
return u.lo.ones_count() + u.hi.ones_count()
|
||||
}
|
||||
|
||||
// str returns the decimal representation of the unsigned integer
|
||||
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] += u8(r % 10)
|
||||
}
|
||||
if q.is_zero() {
|
||||
return buf[i - n..].bytestr()
|
||||
}
|
||||
u = q
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
// uint256_from_dec_str creates a new `unsigned.Uint256` from the given string if possible
|
||||
// The `_` character is allowed as a separator.
|
||||
pub fn uint256_from_dec_str(value string) !Uint256 {
|
||||
mut res := uint256_zero
|
||||
underscore := `_`
|
||||
|
||||
for b_ in value {
|
||||
b := b_ - `0`
|
||||
if b > 9 {
|
||||
// allow _ as a separator in decimal strings
|
||||
if b_ == underscore {
|
||||
continue
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// / -> returns u / v
|
||||
pub fn (u Uint256) / (v Uint256) Uint256 {
|
||||
return u.div(v)
|
||||
}
|
||||
|
||||
// % -> returns u % v
|
||||
pub fn (u Uint256) % (v Uint256) Uint256 {
|
||||
return u.mod(v)
|
||||
}
|
||||
|
||||
// + -> returns u + v
|
||||
pub fn (u Uint256) + (v Uint256) Uint256 {
|
||||
return u.add(v)
|
||||
}
|
||||
|
||||
// - -> returns u - v
|
||||
pub fn (u Uint256) - (v Uint256) Uint256 {
|
||||
return u.sub(v)
|
||||
}
|
||||
|
||||
// * -> returns u * v
|
||||
pub fn (u Uint256) * (v Uint256) Uint256 {
|
||||
return u.mul(v)
|
||||
}
|
||||
|
||||
// < -> returns true if u < v
|
||||
pub fn (u Uint256) < (v Uint256) bool {
|
||||
return u.cmp(v) == -1
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
import math.unsigned
|
||||
|
||||
fn test_str() {
|
||||
// converting from a string and then back to a string
|
||||
// should always give the original string.
|
||||
test_strings := [
|
||||
'0',
|
||||
'1',
|
||||
'9',
|
||||
'10',
|
||||
'11',
|
||||
'99',
|
||||
'100',
|
||||
'101',
|
||||
'65534',
|
||||
'65535',
|
||||
'65536', // 16-bit boundary
|
||||
'65537',
|
||||
'65538',
|
||||
'4294967294',
|
||||
'4294967295',
|
||||
'4294967296', // 32-bit boundary
|
||||
'4294967297',
|
||||
'4294967298',
|
||||
'281474976710654',
|
||||
'281474976710655',
|
||||
'281474976710656', // 48-bit boundary,
|
||||
'281474976710657',
|
||||
'281474976710658',
|
||||
'18446744073709551614',
|
||||
'18446744073709551615',
|
||||
'18446744073709551616', // 64-bit boundary
|
||||
'18446744073709551617',
|
||||
'18446744073709551618',
|
||||
'1208925819614629174706174',
|
||||
'1208925819614629174706175',
|
||||
'1208925819614629174706176', // 80-bit boundary
|
||||
'1208925819614629174706177',
|
||||
'1208925819614629174706178',
|
||||
'79228162514264337593543950334',
|
||||
'79228162514264337593543950335',
|
||||
'79228162514264337593543950336', // 96-bit boundary
|
||||
'79228162514264337593543950337',
|
||||
'79228162514264337593543950338',
|
||||
'5192296858534827628530496329220094',
|
||||
'5192296858534827628530496329220095',
|
||||
'5192296858534827628530496329220096', // 112-bit boundary
|
||||
'5192296858534827628530496329220097',
|
||||
'5192296858534827628530496329220098',
|
||||
'340282366920938463463374607431768211454',
|
||||
'340282366920938463463374607431768211455',
|
||||
'340282366920938463463374607431768211456', // 128-bit boundary
|
||||
'340282366920938463463374607431768211457',
|
||||
'340282366920938463463374607431768211458',
|
||||
'22300745198530623141535718272648361505980414',
|
||||
'22300745198530623141535718272648361505980415',
|
||||
'22300745198530623141535718272648361505980416', // 144-bit boundary
|
||||
'22300745198530623141535718272648361505980417',
|
||||
'22300745198530623141535718272648361505980418',
|
||||
'1461501637330902918203684832716283019655932542974',
|
||||
'1461501637330902918203684832716283019655932542975',
|
||||
'1461501637330902918203684832716283019655932542976', // 160-bit boundary
|
||||
'1461501637330902918203684832716283019655932542977',
|
||||
'1461501637330902918203684832716283019655932542978',
|
||||
'95780971304118053647396689196894323976171195136475134',
|
||||
'95780971304118053647396689196894323976171195136475135',
|
||||
'95780971304118053647396689196894323976171195136475136', // 176-bit boundary
|
||||
'95780971304118053647396689196894323976171195136475137',
|
||||
'95780971304118053647396689196894323976171195136475138',
|
||||
'6277101735386680763835789423207666416102355444464034512894',
|
||||
'6277101735386680763835789423207666416102355444464034512895',
|
||||
'6277101735386680763835789423207666416102355444464034512896', // 192-bit boundary
|
||||
'6277101735386680763835789423207666416102355444464034512897',
|
||||
'6277101735386680763835789423207666416102355444464034512898',
|
||||
'411376139330301510538742295639337626245683966408394965837152254',
|
||||
'411376139330301510538742295639337626245683966408394965837152255',
|
||||
'411376139330301510538742295639337626245683966408394965837152256', // 208-bit boundary
|
||||
'411376139330301510538742295639337626245683966408394965837152257',
|
||||
'411376139330301510538742295639337626245683966408394965837152258',
|
||||
'26959946667150639794667015087019630673637144422540572481103610249214',
|
||||
'26959946667150639794667015087019630673637144422540572481103610249215',
|
||||
'26959946667150639794667015087019630673637144422540572481103610249216', // 224-bit boundary
|
||||
'26959946667150639794667015087019630673637144422540572481103610249217',
|
||||
'26959946667150639794667015087019630673637144422540572481103610249218',
|
||||
'1766847064778384329583297500742918515827483896875618958121606201292619774',
|
||||
'1766847064778384329583297500742918515827483896875618958121606201292619775',
|
||||
'1766847064778384329583297500742918515827483896875618958121606201292619776', // 240-bit boundary
|
||||
'1766847064778384329583297500742918515827483896875618958121606201292619777',
|
||||
'1766847064778384329583297500742918515827483896875618958121606201292619778',
|
||||
'115792089237316195423570985008687907853269984665640564039457584007913129639934',
|
||||
'115792089237316195423570985008687907853269984665640564039457584007913129639935', // 2^256 - 1
|
||||
]
|
||||
|
||||
for ts in test_strings {
|
||||
number := unsigned.uint256_from_dec_str(ts) or {
|
||||
assert false, 'invalid Uint256 string ${ts}'
|
||||
panic('')
|
||||
}
|
||||
|
||||
assert number.str() == ts
|
||||
}
|
||||
|
||||
fundamental_constant := unsigned.uint256_from_64(42)
|
||||
assert fundamental_constant.str() == '42'
|
||||
}
|
||||
|
||||
fn test_ops() {
|
||||
x := unsigned.uint256_from_64(18446744073709551615)
|
||||
y := unsigned.uint256_from_64(18446744073709551615)
|
||||
z := unsigned.uint256_from_dec_str('340282366920938463426481119284349108225') or {
|
||||
assert false
|
||||
panic('')
|
||||
}
|
||||
assert (x * y).str() == '340282366920938463426481119284349108225'
|
||||
assert (x + y).str() == '36893488147419103230'
|
||||
assert (z / unsigned.uint256_from_64(2)).str() == '170141183460469231713240559642174554112'
|
||||
assert (unsigned.uint256_from_dec_str('170141183460469231713240559642174554112') or {
|
||||
panic('')
|
||||
} - unsigned.uint256_from_64(2)).str() == '170141183460469231713240559642174554110'
|
||||
|
||||
assert x == y
|
||||
assert unsigned.uint256_from_dec_str('340282366920938463426481119284349108225') or {
|
||||
assert false
|
||||
panic('')
|
||||
} > y
|
||||
}
|
||||
|
||||
struct LeadingZeros {
|
||||
l unsigned.Uint256
|
||||
r unsigned.Uint256
|
||||
zeros int
|
||||
}
|
||||
|
||||
fn new(x unsigned.Uint128, y unsigned.Uint128) unsigned.Uint256 {
|
||||
return unsigned.Uint256{x, y}
|
||||
}
|
||||
|
||||
fn test_leading_zeros() {
|
||||
tcs := [
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xf000000000000000))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0x8000000000000000))
|
||||
zeros: 65
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xf000000000000000))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xc000000000000000))
|
||||
zeros: 66
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xf000000000000000))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xe000000000000000))
|
||||
zeros: 67
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xffff000000000000))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0xff00000000000000))
|
||||
zeros: 72
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0x000000000000ffff))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0x000000000000ff00))
|
||||
zeros: 120
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0xf000000000000000), unsigned.uint128_from_64(0x01))
|
||||
r: new(unsigned.uint128_from_64(0x4000000000000000), unsigned.uint128_from_64(0x00))
|
||||
zeros: 127
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0xf000000000000000), unsigned.uint128_from_64(0x00))
|
||||
r: new(unsigned.uint128_from_64(0x4000000000000000), unsigned.uint128_from_64(0x00))
|
||||
zeros: 192
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0xf000000000000000), unsigned.uint128_from_64(0x00))
|
||||
r: new(unsigned.uint128_from_64(0x8000000000000000), unsigned.uint128_from_64(0x00))
|
||||
zeros: 193
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0x00))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0x00))
|
||||
zeros: 256
|
||||
},
|
||||
LeadingZeros{
|
||||
l: new(unsigned.uint128_from_64(0x01), unsigned.uint128_from_64(0x00))
|
||||
r: new(unsigned.uint128_from_64(0x00), unsigned.uint128_from_64(0x00))
|
||||
zeros: 255
|
||||
},
|
||||
]
|
||||
|
||||
for tc in tcs {
|
||||
zeros := tc.l.xor(tc.r).leading_zeros()
|
||||
assert zeros == tc.zeros
|
||||
}
|
||||
}
|
||||
|
||||
fn test_separators() {
|
||||
// numbers of varying lengths and a random
|
||||
// scattering of '_' throughout.
|
||||
test_strings := [
|
||||
'_',
|
||||
'__',
|
||||
'_0',
|
||||
'0_',
|
||||
'_0_',
|
||||
'_1',
|
||||
'1_',
|
||||
'_1_',
|
||||
'1_2',
|
||||
'_12',
|
||||
'12_',
|
||||
'12_3',
|
||||
'1_23_4',
|
||||
'12_345',
|
||||
'_123_456_',
|
||||
'1_234_567',
|
||||
'1234_5678',
|
||||
'_123456789',
|
||||
'1234567890_',
|
||||
'0_123_456_789_0',
|
||||
'90_12_345_67890',
|
||||
'8901_234_567890_',
|
||||
'_7890_123456789_0',
|
||||
'678901234_567890',
|
||||
'567890_1234567890',
|
||||
'4567890123__4567890',
|
||||
'_34567890123_4567890',
|
||||
'2345678_90123_4567890',
|
||||
'123456789_01_234567890',
|
||||
'01234567_8901234567890',
|
||||
'9012345678901_234567890__',
|
||||
'8_90123456_78901234567890',
|
||||
'78901234567890_123_4567890',
|
||||
'___67890123_4_5_6_78901234567890___',
|
||||
'567890123_45678901234567890',
|
||||
'45_67890123456789_01234567890',
|
||||
'3456789012_345678901234567890',
|
||||
'234_567890_1234_5__67890_1234567890_',
|
||||
'12345678_90123_456789_0123_4567890',
|
||||
'0_123_456_789_012_345_678_901_234_567_890',
|
||||
'90_123456__78901__234567_8901_234567890',
|
||||
'890123456789012345678901234567_890',
|
||||
'7890_1234567_8901234567890_1234567890',
|
||||
'67890123_45678_901234567_8901234567890',
|
||||
'567890_1234567890_12345678901_234567890',
|
||||
'45678_9012345_6789012345678901234567890_',
|
||||
'34567890123456_789012345678901234567890',
|
||||
'234567_890_1234567890_1234567890_1234567890',
|
||||
'334567890_1234567890_1234567890_1234567890',
|
||||
'340282360_0000000000_0000000000_0000000000',
|
||||
'340282366_9209384634_2648111928_4349108225',
|
||||
'340282366_9209384634_6337460743_1768211455',
|
||||
'6805_647__338418769269_267492148635_36422912',
|
||||
'13611294676837_5385385__34984297_27072845824_',
|
||||
'272225893_53675077077_0699685_94_5414569_1648',
|
||||
'_5444517_8707350154_1541_3993718908291383296',
|
||||
'223007_45198_5306231_4153571_8272648_361505_980416_',
|
||||
'146_150_163_733_090_291_820_368_483_271_628_301_965_593_254_297_6',
|
||||
'6_27_71_01_7353866807638_35789423207666416_1_0_2355444464034512896',
|
||||
'2695994_666715063_979466701508701_9630673637144422_540572481103610249216_',
|
||||
'11579208_923731619_5423570985008687_907853269_98_46_656405640__39457584_00791_3129639935',
|
||||
]
|
||||
|
||||
for ts in test_strings {
|
||||
with := unsigned.uint256_from_dec_str(ts) or {
|
||||
assert false, 'invalid Uint256 string ${ts}'
|
||||
panic('')
|
||||
}
|
||||
|
||||
without := unsigned.uint256_from_dec_str(ts.replace('_', '')) or {
|
||||
assert false, 'invalid Uint256 string ${ts.replace('_', '')}'
|
||||
panic('')
|
||||
}
|
||||
|
||||
assert with == without
|
||||
}
|
||||
}
|
||||
|
||||
fn test_new() {
|
||||
assert unsigned.uint256_new(unsigned.uint128_max, unsigned.uint128_max) == unsigned.uint256_max
|
||||
}
|
||||
|
||||
fn test_rsh() {
|
||||
a :=
|
||||
unsigned.uint256_from_dec_str('115792089237316195423570985008687907853269984665640564039457584007913129639935')!
|
||||
assert a.str() == a.rsh(0).str()
|
||||
assert '57896044618658097711785492504343953926634992332820282019728792003956564819967' == a.rsh(1).str()
|
||||
assert '6277101735386680763835789423207666416102355444464034512895' == a.rsh(64).str()
|
||||
assert '91343852333181432387730302044767688728495783935' == a.rsh(100).str()
|
||||
assert '340282366920938463463374607431768211455' == a.rsh(128).str()
|
||||
assert '170141183460469231731687303715884105727' == a.rsh(129).str()
|
||||
assert unsigned.uint256_zero == a.rsh(256)
|
||||
}
|
||||
|
||||
fn test_lsh() {
|
||||
a := unsigned.uint256_from_dec_str('123')!
|
||||
assert a.lsh(0).str() == a.str()
|
||||
assert a.lsh(1).str() == '246'
|
||||
assert a.lsh(63).str() == '1134474760533137424384'
|
||||
assert a.lsh(64).str() == '2268949521066274848768'
|
||||
assert a.lsh(100).str() == '155921023828072216384094494261248'
|
||||
assert a.lsh(128).str() == '41854731131275431005995076714107490009088'
|
||||
assert a.lsh(200).str() == '197653379443855803891661337357963000110230968235283518742069248'
|
||||
assert a.lsh(300) == unsigned.uint256_zero
|
||||
}
|
||||
|
||||
fn test_rotate_left() {
|
||||
a :=
|
||||
unsigned.uint256_from_dec_str('25514942427378518882041616545065271187265095759155217686057363902268374351523')!
|
||||
assert a.rotate_left(182).str() == '88706376393829417451765793453791860419270208590599379720310994108668904859637'
|
||||
}
|
||||
Reference in new issue
Block a user