package int256 import "math/bits" func udivrem(quot, u []uint64, d *Int) (rem Int) { var dLen int for i := len(d) - 1; i >= 0; i-- { if d[i] != 0 { dLen = i + 1 break } } shift := uint(bits.LeadingZeros64(d[dLen-1])) var dnStorage Int dn := dnStorage[:dLen] for i := dLen - 1; i > 0; i-- { dn[i] = (d[i] << shift) | (d[i-1] >> (64 - shift)) } dn[0] = d[0] << shift var uLen int for i := len(u) - 1; i >= 0; i-- { if u[i] != 0 { uLen = i + 1 break } } if uLen < dLen { copy(rem[:], u) return rem } var unStorage [9]uint64 un := unStorage[:uLen+1] un[uLen] = u[uLen-1] >> (64 - shift) for i := uLen - 1; i > 0; i-- { un[i] = (u[i] << shift) | (u[i-1] >> (64 - shift)) } un[0] = u[0] << shift if dLen == 1 { r := udivremBy1(quot, un, dn[0]) rem.SetUint64(r >> shift) return rem } udivremKnuth(quot, un, dn) for i := 0; i < dLen-1; i++ { rem[i] = (un[i] >> shift) | (un[i+1] << (64 - shift)) } rem[dLen-1] = un[dLen-1] >> shift return rem } func udivremBy1(quot, u []uint64, d uint64) (rem uint64) { reciprocal := reciprocal2by1(d) rem = u[len(u)-1] for j := len(u) - 2; j >= 0; j-- { quot[j], rem = udivrem2by1(rem, u[j], d, reciprocal) } return rem } func udivremKnuth(quot, u, d []uint64) { dLen := len(d) dh := d[dLen-1] dl := d[dLen-2] reciprocal := reciprocal2by1(dh) for j := len(u) - dLen - 1; j >= 0; j-- { u2 := u[j+dLen] u1 := u[j+dLen-1] u0 := u[j+dLen-2] var qhat, rhat uint64 if u2 >= dh { qhat = MAX_UINT64 } else { qhat, rhat = udivrem2by1(u2, u1, dh, reciprocal) ph, pl := bits.Mul64(qhat, dl) if ph > rhat || (ph == rhat && pl > u0) { qhat-- } } borrow := subMulTo(u[j:], d, qhat) u[j+dLen] = u2 - borrow if u2 < borrow { qhat-- u[j+dLen] += addTo(u[j:], d) } quot[j] = qhat } } func reciprocal2by1(d uint64) uint64 { reciprocal, _ := bits.Div64(^d, MAX_UINT64, d) return reciprocal } func udivrem2by1(uh, ul, d, reciprocal uint64) (quot, rem uint64) { qh, ql := bits.Mul64(reciprocal, uh) ql, carry := bits.Add64(ql, ul, 0) qh += uh + carry qh++ r := ul - qh*d if r > ql { qh-- r += d } if r >= d { qh++ r -= d } return qh, r } func subMulTo(x, y []uint64, multiplier uint64) uint64 { var borrow uint64 for i := 0; i < len(y); i++ { s, carry1 := bits.Sub64(x[i], borrow, 0) ph, pl := bits.Mul64(y[i], multiplier) t, carry2 := bits.Sub64(s, pl, 0) x[i] = t borrow = ph + carry1 + carry2 } return borrow } func addTo(x, y []uint64) uint64 { var carry uint64 for i := 0; i < len(y); i++ { x[i], carry = bits.Add64(x[i], y[i], carry) } return carry }