Files
swift-mirror/stdlib/public/core/LegacyInt128.swift.gyb
2025-10-10 14:06:43 -07:00

902 lines
28 KiB
Swift

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
% for signed in [False, True]:
% U = '' if signed else 'U'
% Self = '_Int128' if signed else '_UInt128'
% Other = '_UInt128' if signed else '_Int128'
/// A 128-bit ${'signed' if signed else 'unsigned'} integer type.
internal struct _${U}Int128 {
internal typealias High = ${U}Int64
internal typealias Low = UInt64
/// The low part of the value.
internal var low: Low
internal var _low: Low { low }
/// The high part of the value.
internal var high: High
internal var _high: High { high }
/// Creates a new instance from the given tuple of high and low parts.
///
/// - Parameter value: The tuple to use as the source of the new instance's
/// high and low parts.
internal init(_ value: (high: High, low: Low)) {
self.low = value.low
self.high = value.high
}
internal init(high: High, low: Low) {
self.low = low
self.high = high
}
internal init(_low: Low, _high: High) {
self.low = _low
self.high = _high
}
internal init() {
self.init(high: 0, low: 0)
}
internal init(bitPattern v: ${Other}) {
self.init(high: High(bitPattern: v.high), low: v.low)
}
internal static var zero: Self { Self(high: 0, low: 0) }
internal static var one: Self { Self(high: 0, low: 1) }
}
extension _${U}Int128: CustomStringConvertible {
internal var description: String {
String(self, radix: 10)
}
}
extension _${U}Int128: CustomDebugStringConvertible {
internal var debugDescription: String {
description
}
}
extension _${U}Int128: Equatable {
internal static func == (_ lhs: Self, _ rhs: Self) -> Bool {
return (lhs.high, lhs.low) == (rhs.high, rhs.low)
}
}
extension _${U}Int128: Comparable {
internal static func < (_ lhs: Self, _ rhs: Self) -> Bool {
(lhs.high, lhs.low) < (rhs.high, rhs.low)
}
}
extension _${U}Int128: Hashable {
internal func hash(into hasher: inout Hasher) {
hasher.combine(low)
hasher.combine(high)
}
}
extension _${U}Int128 {
internal var components: (high: High, low: Low) {
@inline(__always) get { (high, low) }
@inline(__always) set { (self.high, self.low) = (newValue.high, newValue.low) }
}
}
extension _${U}Int128: AdditiveArithmetic {
internal static func - (_ lhs: Self, _ rhs: Self) -> Self {
let (result, overflow) = lhs.subtractingReportingOverflow(rhs)
_precondition(!overflow, "Overflow in -")
return result
}
internal static func -= (_ lhs: inout Self, _ rhs: Self) {
let (result, overflow) = lhs.subtractingReportingOverflow(rhs)
_precondition(!overflow, "Overflow in -=")
lhs = result
}
internal static func + (_ lhs: Self, _ rhs: Self) -> Self {
let (result, overflow) = lhs.addingReportingOverflow(rhs)
_precondition(!overflow, "Overflow in +")
return result
}
internal static func += (_ lhs: inout Self, _ rhs: Self) {
let (result, overflow) = lhs.addingReportingOverflow(rhs)
_precondition(!overflow, "Overflow in +=")
lhs = result
}
}
extension _${U}Int128: Numeric {
internal typealias Magnitude = _UInt128
internal var magnitude: Magnitude {
% if signed:
var result = _UInt128(bitPattern: self)
guard high._isNegative else { return result }
result.high = ~result.high
result.low = ~result.low
return result.addingReportingOverflow(.one).partialValue
% else:
return self
% end
}
internal init(_ magnitude: Magnitude) {
self.init(high: High(magnitude.high), low: magnitude.low)
}
internal init<T: BinaryInteger>(_ source: T) {
guard let result = Self(exactly: source) else {
preconditionFailure("Value is outside the representable range")
}
self = result
}
internal init?<T: BinaryInteger>(exactly source: T) {
// Can't represent a negative 'source' if Self is unsigned.
guard Self.isSigned || source >= 0 else {
return nil
}
// Is 'source' entirely representable in Low?
if let low = Low(exactly: source.magnitude) {
self.init(source._isNegative ? (~0, low._twosComplement) : (0, low))
} else {
// At this point we know source.bitWidth > High.bitWidth, or else we
// would've taken the first branch.
let lowInT = source & T(~0 as Low)
let highInT = source >> Low.bitWidth
let low = Low(lowInT)
guard let high = High(exactly: highInT) else {
return nil
}
self.init(high: high, low: low)
}
}
internal static func * (_ lhs: Self, _ rhs: Self) -> Self {
let (result, overflow) = lhs.multipliedReportingOverflow(by: rhs)
_precondition(!overflow, "Overflow in *")
return result
}
internal static func *= (_ lhs: inout Self, _ rhs: Self) {
let (result, overflow) = lhs.multipliedReportingOverflow(by: rhs)
_precondition(!overflow, "Overflow in *=")
lhs = result
}
}
extension _${U}Int128 {
internal struct Words {
internal var _value: _${U}Int128
internal init(_ value: _${U}Int128) {
self._value = value
}
}
}
extension _${U}Int128.Words: RandomAccessCollection {
internal typealias Element = UInt
internal typealias Index = Int
internal typealias Indices = Range<Int>
internal typealias SubSequence = Slice<Self>
internal var count: Int { 128 / UInt.bitWidth }
internal var startIndex: Int { 0 }
internal var endIndex: Int { count }
internal var indices: Indices { startIndex ..< endIndex }
internal func index(after i: Int) -> Int { i + 1 }
internal func index(before i: Int) -> Int { i - 1 }
internal subscript(position: Int) -> UInt {
get {
_precondition(position >= 0 && position < endIndex,
"Word index out of range")
let shift = position &* UInt.bitWidth
_internalInvariant(shift < _${U}Int128.bitWidth)
let r = _wideMaskedShiftRight(
_value.components, UInt64(truncatingIfNeeded: shift))
return r.low._lowWord
}
}
}
extension _${U}Int128: FixedWidthInteger {
@_transparent
internal var _lowWord: UInt {
low._lowWord
}
internal var words: Words {
Words(self)
}
internal static var isSigned: Bool {
${'true' if signed else 'false'}
}
internal static var max: Self {
self.init(high: High.max, low: Low.max)
}
internal static var min: Self {
self.init(high: High.min, low: Low.min)
}
internal static var bitWidth: Int { 128 }
internal func addingReportingOverflow(
_ rhs: Self
) -> (partialValue: Self, overflow: Bool) {
let (r, o) = _wideAddReportingOverflow22(self.components, rhs.components)
return (Self(r), o)
}
internal func subtractingReportingOverflow(
_ rhs: Self
) -> (partialValue: Self, overflow: Bool) {
let (r, o) = _wideSubtractReportingOverflow22(
self.components, rhs.components)
return (Self(r), o)
}
internal func multipliedReportingOverflow(
by rhs: Self
) -> (partialValue: Self, overflow: Bool) {
% if signed:
let isNegative = (self._isNegative != rhs._isNegative && self != .zero && rhs != .zero)
let (p, overflow) = self.magnitude.multipliedReportingOverflow(
by: rhs.magnitude)
let r = _Int128(bitPattern: isNegative ? p._twosComplement : p)
return (r, overflow || (isNegative != r._isNegative))
% else:
let h1 = self.high.multipliedReportingOverflow(by: rhs.low)
let h2 = self.low.multipliedReportingOverflow(by: rhs.high)
let h3 = h1.partialValue.addingReportingOverflow(h2.partialValue)
let (h, l) = self.low.multipliedFullWidth(by: rhs.low)
let high = h3.partialValue.addingReportingOverflow(h)
let overflow = (
(self.high != 0 && rhs.high != 0)
|| h1.overflow || h2.overflow || h3.overflow || high.overflow)
return (Self(high: high.partialValue, low: l), overflow)
% end
}
/// Returns the product of this value and the given 64-bit value, along with a
/// Boolean value indicating whether overflow occurred in the operation.
internal func multipliedReportingOverflow(
by other: UInt64
) -> (partialValue: Self, overflow: Bool) {
% if signed:
let isNegative = self._isNegative && self != .zero && other != .zero
let (p, overflow) = self.magnitude.multipliedReportingOverflow(by: other)
let r = _Int128(bitPattern: isNegative ? p._twosComplement : p)
return (r, overflow || (isNegative != r._isNegative))
% else:
let h1 = self.high.multipliedReportingOverflow(by: other)
let (h2, l) = self.low.multipliedFullWidth(by: other)
let high = h1.partialValue.addingReportingOverflow(h2)
let overflow = h1.overflow || high.overflow
return (Self(high: high.partialValue, low: l), overflow)
% end
}
internal func multiplied(by other: UInt64) -> Self {
let r = multipliedReportingOverflow(by: other)
_precondition(!r.overflow, "Overflow in multiplication")
return r.partialValue
}
internal func quotientAndRemainder(
dividingBy other: Self
) -> (quotient: Self, remainder: Self) {
let (q, r) = _wideDivide22(
self.magnitude.components, by: other.magnitude.components)
let quotient = Self.Magnitude(q)
let remainder = Self.Magnitude(r)
% if signed:
let isNegative = (self.high._isNegative != other.high._isNegative)
let quotient_ = (isNegative
? quotient == Self.min.magnitude ? Self.min : 0 - Self(quotient)
: Self(quotient))
let remainder_ = (self.high._isNegative
? 0 - Self(remainder)
: Self(remainder))
return (quotient_, remainder_)
% else:
return (quotient, remainder)
% end
}
internal func dividedReportingOverflow(
by other: Self
) -> (partialValue: Self, overflow: Bool) {
if other == Self.zero {
return (self, true)
}
if Self.isSigned && other == -1 && self == .min {
return (self, true)
}
return (quotientAndRemainder(dividingBy: other).quotient, false)
}
internal func remainderReportingOverflow(
dividingBy other: Self
) -> (partialValue: Self, overflow: Bool) {
if other == Self.zero {
return (self, true)
}
if Self.isSigned && other == -1 && self == .min {
return (0, true)
}
return (quotientAndRemainder(dividingBy: other).remainder, false)
}
internal func multipliedFullWidth(
by other: Self
) -> (high: Self, low: Magnitude) {
let isNegative = Self.isSigned && (self._isNegative != other._isNegative)
func sum(_ x: Low, _ y: Low) -> (high: Low, low: Low) {
let (sum, overflow) = x.addingReportingOverflow(y)
return (overflow ? 1 : 0, sum)
}
func sum(_ x: Low, _ y: Low, _ z: Low) -> (high: Low, low: Low) {
let s1 = sum(x, y)
let s2 = sum(s1.low, z)
return (s1.high &+ s2.high, s2.low)
}
func sum(
_ x0: Low, _ x1: Low, _ x2: Low, _ x3: Low
) -> (high: Low, low: Low) {
let s1 = sum(x0, x1)
let s2 = sum(x2, x3)
let s = sum(s1.low, s2.low)
return (s1.high &+ s2.high &+ s.high, s.low)
}
let lhs = self.magnitude
let rhs = other.magnitude
let a = rhs.low.multipliedFullWidth(by: lhs.low)
let b = rhs.low.multipliedFullWidth(by: lhs.high)
let c = rhs.high.multipliedFullWidth(by: lhs.low)
let d = rhs.high.multipliedFullWidth(by: lhs.high)
let mid1 = sum(a.high, b.low, c.low)
let mid2 = sum(b.high, c.high, mid1.high, d.low)
let high = _${U}Int128(
high: High(d.high &+ mid2.high), // Note: this addition will never wrap
low: mid2.low)
let low = _UInt128(
high: mid1.low,
low: a.low)
if isNegative {
let (lowComplement, overflow) = (~low).addingReportingOverflow(.one)
return (~high + (overflow ? 1 : 0), lowComplement)
} else {
return (high, low)
}
}
internal func dividingFullWidth(
_ dividend: (high: Self, low: Self.Magnitude)
) -> (quotient: Self, remainder: Self) {
% if signed:
let m = _wideMagnitude22(dividend)
let (quotient, remainder) = self.magnitude.dividingFullWidth(m)
let isNegative = (self.high._isNegative != dividend.high.high._isNegative)
let quotient_ = (isNegative
? (quotient == Self.min.magnitude ? Self.min : 0 - Self(quotient))
: Self(quotient))
let remainder_ = (dividend.high.high._isNegative
? 0 - Self(remainder)
: Self(remainder))
return (quotient_, remainder_)
% else:
let (q, r) = _wideDivide42(
(dividend.high.components, dividend.low.components),
by: self.components)
return (Self(q), Self(r))
% end
}
#if false // This triggers an unexpected type checking issue with `~0` in an
// lldb test
internal static prefix func ~(x: Self) -> Self {
Self(high: ~x.high, low: ~x.low)
}
#endif
internal static func &= (_ lhs: inout Self, _ rhs: Self) {
lhs.low &= rhs.low
lhs.high &= rhs.high
}
internal static func |= (_ lhs: inout Self, _ rhs: Self) {
lhs.low |= rhs.low
lhs.high |= rhs.high
}
internal static func ^= (_ lhs: inout Self, _ rhs: Self) {
lhs.low ^= rhs.low
lhs.high ^= rhs.high
}
internal static func <<= (_ lhs: inout Self, _ rhs: Self) {
if Self.isSigned && rhs._isNegative {
lhs >>= 0 - rhs
return
}
// Shift is larger than this type's bit width.
if rhs.high != High.zero || rhs.low >= Self.bitWidth {
lhs = 0
return
}
lhs &<<= rhs
}
internal static func >>= (_ lhs: inout Self, _ rhs: Self) {
if Self.isSigned && rhs._isNegative {
lhs <<= 0 - rhs
return
}
// Shift is larger than this type's bit width.
if rhs.high != High.zero || rhs.low >= Self.bitWidth {
lhs = lhs._isNegative ? ~0 : 0
return
}
lhs &>>= rhs
}
internal static func &<< (lhs: Self, rhs: Self) -> Self {
Self(_wideMaskedShiftLeft(lhs.components, rhs.low))
}
internal static func &>> (lhs: Self, rhs: Self) -> Self {
Self(_wideMaskedShiftRight(lhs.components, rhs.low))
}
internal static func &<<= (lhs: inout Self, rhs: Self) {
_wideMaskedShiftLeft(&lhs.components, rhs.low)
}
internal static func &>>= (lhs: inout Self, rhs: Self) {
_wideMaskedShiftRight(&lhs.components, rhs.low)
}
internal static func / (
_ lhs: Self, _ rhs: Self
) -> Self {
var lhs = lhs
lhs /= rhs
return lhs
}
internal static func /= (_ lhs: inout Self, _ rhs: Self) {
let (result, overflow) = lhs.dividedReportingOverflow(by: rhs)
_precondition(!overflow, "Overflow in /=")
lhs = result
}
internal static func % (
_ lhs: Self, _ rhs: Self
) -> Self {
var lhs = lhs
lhs %= rhs
return lhs
}
internal static func %= (_ lhs: inout Self, _ rhs: Self) {
let (result, overflow) = lhs.remainderReportingOverflow(dividingBy: rhs)
_precondition(!overflow, "Overflow in %=")
lhs = result
}
internal init(_truncatingBits bits: UInt) {
low = Low(_truncatingBits: bits)
high = High(_truncatingBits: bits >> UInt(Low.bitWidth))
}
internal init(integerLiteral x: Int64) {
self.init(x)
}
internal var leadingZeroBitCount: Int {
(high == High.zero
? High.bitWidth + low.leadingZeroBitCount
: high.leadingZeroBitCount)
}
internal var trailingZeroBitCount: Int {
(low == Low.zero
? Low.bitWidth + high.trailingZeroBitCount
: low.trailingZeroBitCount)
}
internal var nonzeroBitCount: Int {
high.nonzeroBitCount + low.nonzeroBitCount
}
internal var byteSwapped: Self {
Self(
high: High(truncatingIfNeeded: low.byteSwapped),
low: Low(truncatingIfNeeded: high.byteSwapped))
}
}
extension _${U}Int128: Sendable {}
% end
extension BinaryInteger {
@inline(__always)
fileprivate var _isNegative: Bool { self < Self.zero }
}
extension FixedWidthInteger {
@inline(__always)
fileprivate var _twosComplement: Self {
~self &+ 1
}
}
private typealias _Wide2<F: FixedWidthInteger> =
(high: F, low: F.Magnitude)
private typealias _Wide3<F: FixedWidthInteger> =
(high: F, mid: F.Magnitude, low: F.Magnitude)
private typealias _Wide4<F: FixedWidthInteger> =
(high: _Wide2<F>, low: (high: F.Magnitude, low: F.Magnitude))
private func _wideMagnitude22<F: FixedWidthInteger>(
_ v: _Wide2<F>
) -> _Wide2<F.Magnitude> {
var result = (high: F.Magnitude(truncatingIfNeeded: v.high), low: v.low)
guard F.isSigned && v.high._isNegative else { return result }
result.high = ~result.high
result.low = ~result.low
return _wideAddReportingOverflow22(result, (high: 0, low: 1)).partialValue
}
private func _wideAddReportingOverflow22<F: FixedWidthInteger>(
_ lhs: _Wide2<F>, _ rhs: _Wide2<F>
) -> (partialValue: _Wide2<F>, overflow: Bool) {
let (low, lowOverflow) = lhs.low.addingReportingOverflow(rhs.low)
let (high, highOverflow) = lhs.high.addingReportingOverflow(rhs.high)
let overflow = highOverflow || high == F.max && lowOverflow
let result = (high: high &+ (lowOverflow ? 1 : 0), low: low)
return (partialValue: result, overflow: overflow)
}
private func _wideAdd22<F: FixedWidthInteger>(
_ lhs: inout _Wide2<F>, _ rhs: _Wide2<F>
) {
let (result, overflow) = _wideAddReportingOverflow22(lhs, rhs)
_precondition(!overflow, "Overflow in +")
lhs = result
}
private func _wideAddReportingOverflow33<F: FixedWidthInteger>(
_ lhs: _Wide3<F>, _ rhs: _Wide3<F>
) -> (
partialValue: _Wide3<F>,
overflow: Bool
) {
let (low, lowOverflow) =
_wideAddReportingOverflow22((lhs.mid, lhs.low), (rhs.mid, rhs.low))
let (high, highOverflow) = lhs.high.addingReportingOverflow(rhs.high)
let result = (high: high &+ (lowOverflow ? 1 : 0), mid: low.high, low: low.low)
let overflow = highOverflow || (high == F.max && lowOverflow)
return (partialValue: result, overflow: overflow)
}
private func _wideSubtractReportingOverflow22<F: FixedWidthInteger>(
_ lhs: _Wide2<F>, _ rhs: _Wide2<F>
) -> (partialValue: (high: F, low: F.Magnitude), overflow: Bool) {
let (low, lowOverflow) = lhs.low.subtractingReportingOverflow(rhs.low)
let (high, highOverflow) = lhs.high.subtractingReportingOverflow(rhs.high)
let result = (high: high &- (lowOverflow ? 1 : 0), low: low)
let overflow = highOverflow || high == F.min && lowOverflow
return (partialValue: result, overflow: overflow)
}
private func _wideSubtract22<F: FixedWidthInteger>(
_ lhs: inout _Wide2<F>, _ rhs: _Wide2<F>
) {
let (result, overflow) = _wideSubtractReportingOverflow22(lhs, rhs)
_precondition(!overflow, "Overflow in -")
lhs = result
}
private func _wideSubtractReportingOverflow33<F: FixedWidthInteger>(
_ lhs: _Wide3<F>, _ rhs: _Wide3<F>
) -> (
partialValue: _Wide3<F>,
overflow: Bool
) {
let (low, lowOverflow) =
_wideSubtractReportingOverflow22((lhs.mid, lhs.low), (rhs.mid, rhs.low))
let (high, highOverflow) = lhs.high.subtractingReportingOverflow(rhs.high)
let result = (high: high &- (lowOverflow ? 1 : 0), mid: low.high, low: low.low)
let overflow = highOverflow || (high == F.min && lowOverflow)
return (partialValue: result, overflow: overflow)
}
private func _wideMaskedShiftLeft<F: FixedWidthInteger>(
_ lhs: _Wide2<F>, _ rhs: F.Magnitude
) -> _Wide2<F> {
let bitWidth = F.bitWidth + F.Magnitude.bitWidth
_internalInvariant(bitWidth.nonzeroBitCount == 1)
// Mask rhs by the bit width of the wide value.
let rhs = rhs & F.Magnitude(bitWidth &- 1)
guard rhs < F.Magnitude.bitWidth else {
let s = rhs &- F.Magnitude(F.Magnitude.bitWidth)
return (high: F(truncatingIfNeeded: lhs.low &<< s), low: 0)
}
guard rhs != F.Magnitude.zero else { return lhs }
var high = lhs.high &<< F(rhs)
let rollover = F.Magnitude(F.bitWidth) &- rhs
high |= F(truncatingIfNeeded: lhs.low &>> rollover)
let low = lhs.low &<< rhs
return (high, low)
}
private func _wideMaskedShiftLeft<F: FixedWidthInteger>(
_ lhs: inout _Wide2<F>, _ rhs: F.Magnitude
) {
lhs = _wideMaskedShiftLeft(lhs, rhs)
}
private func _wideMaskedShiftRight<F: FixedWidthInteger>(
_ lhs: _Wide2<F>, _ rhs: F.Magnitude
) -> _Wide2<F> {
let bitWidth = F.bitWidth + F.Magnitude.bitWidth
_internalInvariant(bitWidth.nonzeroBitCount == 1)
// Mask rhs by the bit width of the wide value.
let rhs = rhs & F.Magnitude(bitWidth &- 1)
guard rhs < F.bitWidth else {
let s = F(rhs &- F.Magnitude(F.bitWidth))
return (
high: lhs.high._isNegative ? ~0 : 0,
low: F.Magnitude(truncatingIfNeeded: lhs.high &>> s))
}
guard rhs != F.zero else { return lhs }
var low = lhs.low &>> rhs
let rollover = F(F.bitWidth) &- F(rhs)
low |= F.Magnitude(truncatingIfNeeded: lhs.high &<< rollover)
let high = lhs.high &>> rhs
return (high, low)
}
private func _wideMaskedShiftRight<F: FixedWidthInteger>(
_ lhs: inout _Wide2<F>, _ rhs: F.Magnitude
) {
lhs = _wideMaskedShiftRight(lhs, rhs)
}
/// Returns the quotient and remainder after dividing a triple-width magnitude
/// `lhs` by a double-width magnitude `rhs`.
///
/// This operation is conceptually that described by Burnikel and Ziegler
/// (1998).
private func _wideDivide32<F: FixedWidthInteger & UnsignedInteger>(
_ lhs: _Wide3<F>, by rhs: _Wide2<F>
) -> (quotient: F, remainder: _Wide2<F>) {
// The following invariants are guaranteed to hold by dividingFullWidth or
// quotientAndRemainder before this function is invoked:
#if !$Embedded
// TODO: Investigate why this fails to compile in embedded Swift with
// assertions off
_internalInvariant(lhs.high != F.zero)
_internalInvariant(rhs.high.leadingZeroBitCount == 0)
#endif
_internalInvariant((high: lhs.high, low: lhs.mid) < rhs)
// Estimate the quotient with a 2/1 division using just the top digits.
var quotient = (lhs.high == rhs.high
? F.max
: rhs.high.dividingFullWidth((high: lhs.high, low: lhs.mid)).quotient)
// Compute quotient * rhs.
// TODO: This could be performed more efficiently.
let p1 = quotient.multipliedFullWidth(by: F(rhs.low))
let p2 = quotient.multipliedFullWidth(by: rhs.high)
let product = _wideAddReportingOverflow33(
(high: F.zero, mid: F.Magnitude(p1.high), low: p1.low),
(high: p2.high, mid: p2.low, low: .zero)).partialValue
// Compute the remainder after decrementing quotient as necessary.
var remainder = lhs
while remainder < product {
quotient = quotient &- 1
remainder = _wideAddReportingOverflow33(
remainder,
(high: F.zero, mid: F.Magnitude(rhs.high), low: rhs.low)).partialValue
}
remainder = _wideSubtractReportingOverflow33(remainder, product).partialValue
_internalInvariant(remainder.high == 0)
return (quotient, (high: F(remainder.mid), low: remainder.low))
}
/// Returns the quotient and remainder after dividing a double-width
/// magnitude `lhs` by a double-width magnitude `rhs`.
private func _wideDivide22<F: FixedWidthInteger & UnsignedInteger>(
_ lhs: _Wide2<F>, by rhs: _Wide2<F>
) -> (quotient: _Wide2<F>, remainder: _Wide2<F>) {
guard _fastPath(rhs > (F.zero, F.Magnitude.zero)) else {
fatalError("Division by zero")
}
guard rhs < lhs else {
if _fastPath(rhs > lhs) { return (quotient: (0, 0), remainder: lhs) }
return (quotient: (0, 1), remainder: (0, 0))
}
if lhs.high == F.zero {
let (quotient, remainder) =
lhs.low.quotientAndRemainder(dividingBy: rhs.low)
return ((0, quotient), (0, remainder))
}
if rhs.high == F.zero {
let (x, a) = lhs.high.quotientAndRemainder(dividingBy: F(rhs.low))
let (y, b) = (a == F.zero
? lhs.low.quotientAndRemainder(dividingBy: rhs.low)
: rhs.low.dividingFullWidth((F.Magnitude(a), lhs.low)))
return (quotient: (high: x, low: y), remainder: (high: 0, low: b))
}
// Left shift both rhs and lhs, then divide and right shift the remainder.
let shift = F.Magnitude(rhs.high.leadingZeroBitCount)
let rollover = F.Magnitude(F.bitWidth + F.Magnitude.bitWidth) &- shift
let rhs = _wideMaskedShiftLeft(rhs, shift)
let high = _wideMaskedShiftRight(lhs, rollover).low
let lhs = _wideMaskedShiftLeft(lhs, shift)
let (quotient, remainder) = _wideDivide32(
(F(high), F.Magnitude(lhs.high), lhs.low), by: rhs)
return (
quotient: (high: 0, low: F.Magnitude(quotient)),
remainder: _wideMaskedShiftRight(remainder, shift))
}
/// Returns the quotient and remainder after dividing a quadruple-width
/// magnitude `lhs` by a double-width magnitude `rhs`.
private func _wideDivide42<F: FixedWidthInteger & UnsignedInteger>(
_ lhs: _Wide4<F>, by rhs: _Wide2<F>
) -> (quotient: _Wide2<F>, remainder: _Wide2<F>) {
guard _fastPath(rhs > (F.zero, F.Magnitude.zero)) else {
fatalError("Division by zero")
}
guard _fastPath(rhs >= lhs.high) else {
fatalError("Division results in an overflow")
}
if lhs.high == (F.zero, F.Magnitude.zero) {
return _wideDivide22((high: F(lhs.low.high), low: lhs.low.low), by: rhs)
}
if rhs.high == F.zero {
let a = F.Magnitude(lhs.high.high) % rhs.low
let b = (a == F.Magnitude.zero
? lhs.high.low % rhs.low
: rhs.low.dividingFullWidth((a, lhs.high.low)).remainder)
let (x, c) = (b == F.Magnitude.zero
? lhs.low.high.quotientAndRemainder(dividingBy: rhs.low)
: rhs.low.dividingFullWidth((b, lhs.low.high)))
let (y, d) = (c == F.Magnitude.zero
? lhs.low.low.quotientAndRemainder(dividingBy: rhs.low)
: rhs.low.dividingFullWidth((c, lhs.low.low)))
return (quotient: (high: F(x), low: y), remainder: (high: 0, low: d))
}
// Left shift both rhs and lhs, then divide and right shift the remainder.
let shift = F.Magnitude(rhs.high.leadingZeroBitCount)
let rollover = F.Magnitude(F.bitWidth + F.Magnitude.bitWidth) &- shift
let rhs = _wideMaskedShiftLeft(rhs, shift)
let lh1 = _wideMaskedShiftLeft(lhs.high, shift)
let lh2 = _wideMaskedShiftRight(lhs.low, rollover)
let lhs = (
high: (high: lh1.high | F(lh2.high), low: lh1.low | lh2.low),
low: _wideMaskedShiftLeft(lhs.low, shift))
if
lhs.high.high == F.Magnitude.zero,
(high: F(lhs.high.low), low: lhs.low.high) < rhs
{
let (quotient, remainder) = _wideDivide32(
(F(lhs.high.low), lhs.low.high, lhs.low.low),
by: rhs)
return (
quotient: (high: 0, low: F.Magnitude(quotient)),
remainder: _wideMaskedShiftRight(remainder, shift))
}
let (x, a) = _wideDivide32(
(lhs.high.high, lhs.high.low, lhs.low.high), by: rhs)
let (y, b) = _wideDivide32((a.high, a.low, lhs.low.low), by: rhs)
return (
quotient: (high: x, low: F.Magnitude(y)),
remainder: _wideMaskedShiftRight(b, shift))
}
extension _UInt128: UnsignedInteger {}
extension _Int128: SignedNumeric, SignedInteger {}
%{
# This finds the magic numbers for signed division by a constant, following
# the algorithm described in [Warren 2013, page 212].
def magic(w, d):
nc = (2 ** (w - 1)) // d * d - 1
for p in range(2, 2 * w):
pp = 2 ** p
delta = d - pp % d
if pp > nc * delta:
m = (pp + delta) // d
overflow = m > 2 ** (w - 1) - 1
if overflow:
m = m - 2 ** w
w2 = w // 2
ml = m & (2 ** w2 - 1)
mh = m >> w2
return (mh, ml, p - w, overflow)
raise RuntimeError("No magic found")
}%
% for exp in [18, 15, 12, 9, 6, 3]:
% d = 10 ** exp
% (mh, ml, s, overflow) = magic(128, d)
extension _Int128 {
internal func dividedBy1e${exp}() -> (quotient: Self, remainder: Self) {
let m = _Int128(high: ${mh}, low: ${ml})
var q = self.multipliedFullWidth(by: m).high
% if overflow:
q &+= self
% end
% if s > 0:
q &>>= ${s}
% end
// Add 1 to q if self is negative
q &+= _Int128(bitPattern: _UInt128(bitPattern: self) &>> 127)
let r = self &- q &* (${d} as _Int128)
return (q, r)
}
}
% end