Skip to content

Commit 2cc1e2a

Browse files
committed
[stdlib] Int128: Add direct division by some constant powers of ten
1 parent b963f7c commit 2cc1e2a

File tree

1 file changed

+45
-3
lines changed

1 file changed

+45
-3
lines changed

stdlib/public/core/Int128.swift.gyb

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

800801
extension _UInt128: UnsignedInteger {}
801802
extension _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

Comments
 (0)