Skip to content

Commit e62ed47

Browse files
authored
math.unsigned: fix quo_rem(), add tests (#24859)
1 parent 2c4845a commit e62ed47

2 files changed

Lines changed: 45 additions & 27 deletions

File tree

‎vlib/math/unsigned/uint128.v‎

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -267,34 +267,32 @@ pub fn (u Uint128) quo_rem_64(v u64) (Uint128, u64) {
267267
}
268268

269269
// quo_rem returns q = u/v and r = u%v
270-
pub fn (u Uint128) quo_rem(v Uint128) (Uint128, Uint128) {
271-
mut q := Uint128{}
272-
mut r := Uint128{}
273-
if v.hi == 0 {
274-
mut r64 := u64(0)
275-
q, r64 = u.quo_rem_64(v.lo)
276-
r = Uint128{r64, 0}
277-
} else {
278-
n := bits.leading_zeros_64(v.hi)
279-
v1 := v.lsh(u32(n))
280-
u1 := v.rsh(1)
281-
282-
mut tq, _ := bits.div_64(u1.hi, u1.lo, v1.hi)
283-
tq >>= u64(64 - n)
284-
if tq != 0 {
285-
tq -= 1
286-
}
287-
288-
q = Uint128{tq, 0}
289-
r = u - v.mul_64(tq)
290-
291-
if r.cmp(v) >= 0 {
292-
q = q.add_64(1)
293-
r = r - v
294-
}
270+
pub fn (a Uint128) quo_rem(b Uint128) (Uint128, Uint128) {
271+
if a < b {
272+
return uint128_zero, a
295273
}
296-
297-
return q, r
274+
if b.is_zero() {
275+
panic('Division by zero')
276+
}
277+
if b.hi == 0 {
278+
quotient, remainder := a.quo_rem_64(b.lo)
279+
return quotient, uint128_from_64(remainder)
280+
}
281+
shift := u32(b.leading_zeros() - a.leading_zeros())
282+
mut af := a
283+
mut bf := b.lsh(shift)
284+
mut quotient := uint128_zero
285+
286+
for _ in 0 .. shift + 1 {
287+
quotient = quotient.lsh(1)
288+
diff_result := bf.add(af.not())
289+
s := u64(i64(diff_result.hi) >> 63)
290+
quotient.lo |= s & 1
291+
mask := uint128_new(s, s)
292+
af = af.sub(bf.and(mask))
293+
bf = bf.rsh(1)
294+
}
295+
return quotient, af
298296
}
299297

300298
// lsh returns u << n

‎vlib/math/unsigned/uint128_test.v‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import math.big
12
import math.unsigned
23

34
fn test_str() {
@@ -193,3 +194,22 @@ fn test_rsh() {
193194
assert '1' == a.rsh(127).str()
194195
assert unsigned.uint128_zero == a.rsh(200)
195196
}
197+
198+
fn test_quo_rem() {
199+
for a_lo in 0 .. 16 {
200+
for a_hi in 0 .. 16 {
201+
for b_lo in 0 .. 16 {
202+
for b_hi in 0 .. 16 {
203+
a := unsigned.uint128_new(u64(1 << a_lo), u64(1 << a_hi))
204+
b := unsigned.uint128_new(u64(1 << b_lo), u64(1 << b_hi))
205+
big_a := big.integer_from_string(a.str())!
206+
big_b := big.integer_from_string(b.str())!
207+
q, r := a.quo_rem(b)
208+
big_q, big_r := big_a.div_mod(big_b)
209+
assert q.str() == big_q.str()
210+
assert r.str() == big_r.str()
211+
}
212+
}
213+
}
214+
}
215+
}

0 commit comments

Comments
 (0)