71 lines
1.4 KiB
Go
71 lines
1.4 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This file provides a generic Go implementation of uint128 divided by uint64.
|
|
|
|
// The code is derived from Go's generic math/big.divWW_g
|
|
// (src/math/big/arith.go), but is only used on ARM64.
|
|
|
|
package time
|
|
|
|
import "math/bits"
|
|
|
|
type word uint
|
|
|
|
const (
|
|
_W = bits.UintSize // word size in bits
|
|
_W2 = _W / 2 // half word size in bits
|
|
_B2 = 1 << _W2 // half digit base
|
|
_M2 = _B2 - 1 // half digit mask
|
|
)
|
|
|
|
// nlz returns the number of leading zeros in x.
|
|
// Wraps bits.LeadingZeros call for convenience.
|
|
func nlz(x word) uint {
|
|
return uint(bits.LeadingZeros(uint(x)))
|
|
}
|
|
|
|
// q = (u1<<_W + u0 - r)/y
|
|
// Adapted from Warren, Hacker's Delight, p. 152.
|
|
func divWW(u1, u0, v word) (q, r word) {
|
|
if u1 >= v {
|
|
return 1<<_W - 1, 1<<_W - 1
|
|
}
|
|
|
|
s := nlz(v)
|
|
v <<= s
|
|
|
|
vn1 := v >> _W2
|
|
vn0 := v & _M2
|
|
un32 := u1<<s | u0>>(_W-s)
|
|
un10 := u0 << s
|
|
un1 := un10 >> _W2
|
|
un0 := un10 & _M2
|
|
q1 := un32 / vn1
|
|
rhat := un32 - q1*vn1
|
|
|
|
for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
|
|
q1--
|
|
rhat += vn1
|
|
|
|
if rhat >= _B2 {
|
|
break
|
|
}
|
|
}
|
|
|
|
un21 := un32*_B2 + un1 - q1*v
|
|
q0 := un21 / vn1
|
|
rhat = un21 - q0*vn1
|
|
|
|
for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
|
|
q0--
|
|
rhat += vn1
|
|
if rhat >= _B2 {
|
|
break
|
|
}
|
|
}
|
|
|
|
return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
|
|
}
|