@@ -282,9 +282,7 @@ extension _${U}Int128: FixedWidthInteger {
282282 self.magnitude.components, by: other.magnitude.components)
283283 let quotient = Self.Magnitude(q)
284284 let remainder = Self.Magnitude(r)
285- guard Self.isSigned else {
286- return (Self(quotient), Self(remainder))
287- }
285+ % if signed:
288286 let isNegative = (self.high._isNegative != other.high._isNegative)
289287 let quotient_ = (isNegative
290288 ? quotient == Self.min.magnitude ? Self.min : 0 - Self(quotient)
@@ -293,6 +291,9 @@ extension _${U}Int128: FixedWidthInteger {
293291 ? 0 - Self(remainder)
294292 : Self(remainder))
295293 return (quotient_, remainder_)
294+ % else:
295+ return (quotient, remainder)
296+ % end
296297 }
297298
298299 internal func dividedReportingOverflow(
@@ -799,3 +800,44 @@ private func _wideDivide42<F: FixedWidthInteger & UnsignedInteger>(
799800
800801extension _UInt128: UnsignedInteger {}
801802extension _Int128: SignedNumeric, SignedInteger {}
803+
804+ %{
805+ # This finds the magic numbers for signed division by a constant, following
806+ # the algorithm described in [Warren 2013, page 212].
807+ def magic(w, d):
808+ nc = (2 ** (w - 1)) // d * d - 1
809+ for p in range(2, 2 * w):
810+ pp = 2 ** p
811+ delta = d - pp % d
812+ if pp > nc * delta:
813+ m = (pp + delta) // d
814+ overflow = m > 2 ** (w - 1) - 1
815+ if overflow:
816+ m = m - 2 ** w
817+ w2 = w // 2
818+ ml = m & (2 ** w2 - 1)
819+ mh = m >> w2
820+ return (mh, ml, p - w, overflow)
821+ raise RuntimeError("No magic found")
822+ }%
823+
824+ % for exp in [18, 15, 12, 9, 6, 3]:
825+ % d = 10 ** exp
826+ % (mh, ml, s, overflow) = magic(128, d)
827+ extension _Int128 {
828+ internal func dividedBy1e${exp}() -> (quotient: Self, remainder: Self) {
829+ let m = _Int128(high: ${mh}, low: ${ml})
830+ var q = self.multipliedFullWidth(by: m).high
831+ % if overflow:
832+ q &+= self
833+ % end
834+ % if s > 0:
835+ q &>>= ${s}
836+ % end
837+ // Add 1 to q if self is negative
838+ q &+= _Int128(bitPattern: _UInt128(bitPattern: self) &>> 127)
839+ let r = self &- q &* (${d} as _Int128)
840+ return (q, r)
841+ }
842+ }
843+ % end
0 commit comments