math.bits: fix bits.div_64 behaviour for leading_zeros_64(y) = 0
parent
315b2deda9
commit
2a3a4cfc84
|
@ -429,30 +429,51 @@ pub fn div_64(hi u64, lo u64, y1 u64) (u64, u64) {
|
||||||
y <<= s
|
y <<= s
|
||||||
yn1 := y >> 32
|
yn1 := y >> 32
|
||||||
yn0 := y & bits.mask32
|
yn0 := y & bits.mask32
|
||||||
un32 := (hi << s) | (lo >> (64 - s))
|
ss1 := (hi << s)
|
||||||
|
xxx := 64 - s
|
||||||
|
mut ss2 := lo >> xxx
|
||||||
|
if xxx == 64 {
|
||||||
|
// in Go, shifting right a u64 number, 64 times produces 0 *always*.
|
||||||
|
// See https://go.dev/ref/spec
|
||||||
|
// > The shift operators implement arithmetic shifts if the left operand
|
||||||
|
// > is a signed integer and logical shifts if it is an unsigned integer.
|
||||||
|
// > There is no upper limit on the shift count.
|
||||||
|
// > Shifts behave as if the left operand is shifted n times by 1 for a shift count of n.
|
||||||
|
// > As a result, x << 1 is the same as x*2 and x >> 1 is the same as x/2
|
||||||
|
// > but truncated towards negative infinity.
|
||||||
|
//
|
||||||
|
// In V, that is currently left to whatever C is doing, which is apparently a NOP.
|
||||||
|
// This function was a direct port of https://cs.opensource.google/go/go/+/refs/tags/go1.17.6:src/math/bits/bits.go;l=512,
|
||||||
|
// so we have to use the Go behaviour.
|
||||||
|
// TODO: reconsider whether we need to adopt it for our shift ops, or just use function wrappers that do it.
|
||||||
|
ss2 = 0
|
||||||
|
}
|
||||||
|
un32 := ss1 | ss2
|
||||||
un10 := lo << s
|
un10 := lo << s
|
||||||
un1 := un10 >> 32
|
un1 := un10 >> 32
|
||||||
un0 := un10 & bits.mask32
|
un0 := un10 & bits.mask32
|
||||||
mut q1 := un32 / yn1
|
mut q1 := un32 / yn1
|
||||||
mut rhat := un32 - q1 * yn1
|
mut rhat := un32 - (q1 * yn1)
|
||||||
for q1 >= bits.two32 || q1 * yn0 > bits.two32 * rhat + un1 {
|
for (q1 >= bits.two32) || (q1 * yn0) > ((bits.two32 * rhat) + un1) {
|
||||||
q1--
|
q1--
|
||||||
rhat += yn1
|
rhat += yn1
|
||||||
if rhat >= bits.two32 {
|
if rhat >= bits.two32 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
un21 := un32 * bits.two32 + un1 - q1 * y
|
un21 := (un32 * bits.two32) + (un1 - (q1 * y))
|
||||||
mut q0 := un21 / yn1
|
mut q0 := un21 / yn1
|
||||||
rhat = un21 - q0 * yn1
|
rhat = un21 - q0 * yn1
|
||||||
for q0 >= bits.two32 || q0 * yn0 > bits.two32 * rhat + un0 {
|
for (q0 >= bits.two32) || (q0 * yn0) > ((bits.two32 * rhat) + un0) {
|
||||||
q0--
|
q0--
|
||||||
rhat += yn1
|
rhat += yn1
|
||||||
if rhat >= bits.two32 {
|
if rhat >= bits.two32 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return q1 * bits.two32 + q0, (un21 * bits.two32 + un0 - q0 * y) >> s
|
qq := ((q1 * bits.two32) + q0)
|
||||||
|
rr := ((un21 * bits.two32) + un0 - (q0 * y)) >> s
|
||||||
|
return qq, rr
|
||||||
}
|
}
|
||||||
|
|
||||||
// rem_32 returns the remainder of (hi, lo) divided by y. Rem32 panics
|
// rem_32 returns the remainder of (hi, lo) divided by y. Rem32 panics
|
||||||
|
|
|
@ -286,3 +286,12 @@ fn test_bits() {
|
||||||
assert rem == rem_64(hi, lo, y)
|
assert rem == rem_64(hi, lo, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_div_64_edge_cases() {
|
||||||
|
qq, rr := div_64(10, 12, 11)
|
||||||
|
assert qq == 16769767339735956015
|
||||||
|
assert rr == 7
|
||||||
|
q, r := div_64(0, 23, 10000000000000000000)
|
||||||
|
assert q == 0
|
||||||
|
assert r == 23
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue