Skip to content

Commit

Permalink
quotientAndRemainderReportingOverflow(dividingBy:) (#84) (#87) (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
oscbyspro committed Apr 21, 2023
1 parent 91d5464 commit e6c9130
Show file tree
Hide file tree
Showing 8 changed files with 231 additions and 116 deletions.
38 changes: 38 additions & 0 deletions Sources/ANKFoundation/ANKBinaryInteger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,29 @@ public protocol ANKBinaryInteger: ANKBitPatternConvertible, BinaryInteger, Senda
///
@inlinable func quotientAndRemainder(dividingBy divisor: Self) -> QR<Self, Self>

/// Returns the quotient and remainder of this value divided by the given value,
/// and returns a value indicating whether overflow occurred. In the case of overflow,
/// the result is either truncated or, if undefined, this value.
///
/// ```swift
/// let a = Int8(-128).quotientAndRemainderReportingOverflow(dividingBy: Int8( 3))
/// a.partialValue.quotient // Int8( -42)
/// a.partialValue.remainder // Int8( 2)
/// a.overflow // false
///
/// let b = Int8(-128).quotientAndRemainderReportingOverflow(dividingBy: Int8( 0))
/// b.partialValue.quotient // Int8(-128)
/// b.partialValue.remainder // Int8(-128)
/// b.overflow // true
///
/// let c = Int8(-128).quotientAndRemainderReportingOverflow(dividingBy: Int8(-1))
/// c.partialValue.quotient // Int8(-128)
/// c.partialValue.remainder // Int8( 0)
/// c.overflow // true
/// ```
///
@inlinable func quotientAndRemainderReportingOverflow(dividingBy divisor: Self) -> PVO<QR<Self, Self>>

//=------------------------------------------------------------------------=
// MARK: Details x Two's Complement
//=------------------------------------------------------------------------=
Expand Down Expand Up @@ -260,6 +283,21 @@ extension ANKBinaryInteger where Self: FixedWidthInteger {
precondition(!pvo.overflow)
return pvo.partialValue as Self
}

/// Returns the quotient and remainder of this value divided by the given value.
///
/// ```swift
/// Int8( 7).quotientAndRemainder(dividingBy: Int8( 3)) // (quotient: Int8( 2), remainder: Int8( 1))
/// Int8( 7).quotientAndRemainder(dividingBy: Int8(-3)) // (quotient: Int8(-2), remainder: Int8( 1))
/// Int8(-7).quotientAndRemainder(dividingBy: Int8( 3)) // (quotient: Int8(-2), remainder: Int8(-1))
/// Int8(-7).quotientAndRemainder(dividingBy: Int8(-3)) // (quotient: Int8( 2), remainder: Int8(-1))
/// ```
///
@_transparent public func quotientAndRemainder(dividingBy divisor: Self) -> QR<Self, Self> {
let qro: PVO<QR<Self, Self>> = self.quotientAndRemainderReportingOverflow(dividingBy: divisor)
precondition(!qro.overflow)
return qro.partialValue as QR<Self, Self>
}
}

//*============================================================================*
Expand Down
17 changes: 12 additions & 5 deletions Sources/ANKFoundation/ANKCoreInteger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ extension ANKCoreInteger {
return pvo.overflow as Bool
}

@_transparent public mutating func multiplyFullWidth(by amount: Self) -> Self {
let hl: HL<Self, Magnitude> = self.multipliedFullWidth(by: amount)
self = Self(bitPattern: hl.low)
return hl.high as Self
}

@_transparent public mutating func divideReportingOverflow(by amount: Self) -> Bool {
let pvo: PVO<Self> = self.dividedReportingOverflow(by: amount)
self = pvo.partialValue
Expand All @@ -105,11 +111,12 @@ extension ANKCoreInteger {
self = pvo.partialValue
return pvo.overflow as Bool
}

@_transparent public mutating func multiplyFullWidth(by amount: Self) -> Self {
let hl: HL<Self, Magnitude> = self.multipliedFullWidth(by: amount)
self = Self(bitPattern: hl.low)
return hl.high as Self

@_transparent public func quotientAndRemainderReportingOverflow(dividingBy divisor: Self) -> PVO<QR<Self, Self>> {
let quotient: PVO<Self> = self.dividedReportingOverflow(by: divisor)
let remainder: PVO<Self> = self.remainderReportingOverflow(dividingBy: divisor)
assert(quotient.overflow == remainder.overflow)
return PVO(QR(quotient.partialValue, remainder.partialValue), quotient.overflow)
}

//=------------------------------------------------------------------------=
Expand Down
38 changes: 38 additions & 0 deletions Sources/ANKFoundation/ANKLargeBinaryInteger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,29 @@ public protocol ANKLargeBinaryInteger<Digit>: ANKBinaryInteger where Magnitude:
///
@inlinable func quotientAndRemainder(dividingBy divisor: Digit) -> QR<Self, Digit>

/// Returns the quotient and remainder of this value divided by the given value,
/// and returns a value indicating whether overflow occurred. In the case of overflow,
/// the result is either truncated or, if undefined, this value.
///
/// ```swift
/// let a = Int256( 7).quotientAndRemainderReportingOverflow(dividingBy: Int( 3))
/// a.partialValue.quotient // Int256( 2)
/// a.partialValue.remainder // Int256( 1)
/// a.overflow // false
///
/// let b = Int256.min.quotientAndRemainderReportingOverflow(dividingBy: Int( 0))
/// b.partialValue.quotient // Int256.min
/// b.partialValue.remainder // Int256.min
/// b.overflow // true
///
/// let c = Int256.min.quotientAndRemainderReportingOverflow(dividingBy: Int(-1))
/// c.partialValue.quotient // Int256.min
/// c.partialValue.remainder // Int256( 0)
/// c.overflow // true
/// ```
///
@inlinable func quotientAndRemainderReportingOverflow(dividingBy divisor: Digit) -> PVO<QR<Self, Digit>>

//=------------------------------------------------------------------------=
// MARK: Details x Multiplication
//=------------------------------------------------------------------------=
Expand Down Expand Up @@ -294,6 +317,21 @@ extension ANKLargeBinaryInteger {
precondition(!pvo.overflow)
return pvo.partialValue as Digit
}

/// Returns the quotient and remainder of this value divided by the given value.
///
/// ```swift
/// Int256( 7).quotientAndRemainder(dividingBy: Int( 3)) // (quotient: Int256( 2), remainder: Int( 1))
/// Int256( 7).quotientAndRemainder(dividingBy: Int(-3)) // (quotient: Int256(-2), remainder: Int( 1))
/// Int256(-7).quotientAndRemainder(dividingBy: Int( 3)) // (quotient: Int256(-2), remainder: Int(-1))
/// Int256(-7).quotientAndRemainder(dividingBy: Int(-3)) // (quotient: Int256( 2), remainder: Int(-1))
/// ```
///
@_disfavoredOverload @_transparent public func quotientAndRemainder(dividingBy divisor: Digit) -> QR<Self, Digit> {
let qro: PVO<QR<Self, Digit>> = self.quotientAndRemainderReportingOverflow(dividingBy: divisor)
precondition(!qro.overflow)
return qro.partialValue as QR<Self, Digit>
}
}

//*============================================================================*
Expand Down
80 changes: 38 additions & 42 deletions Sources/ANKFullWidthKit/ANKFullWidth+Division+Digit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,66 +19,59 @@ extension ANKFullWidth {
// MARK: Transformations
//=------------------------------------------------------------------------=

@_disfavoredOverload @inlinable public mutating func divideReportingOverflow(by divisor: Digit) -> Bool {
@_disfavoredOverload @_transparent public mutating func divideReportingOverflow(by divisor: Digit) -> Bool {
let pvo: PVO<Self> = self.dividedReportingOverflow(by: divisor)
self = pvo.partialValue
return pvo.overflow as Bool
}

@_disfavoredOverload @inlinable public func dividedReportingOverflow(by divisor: Digit) -> PVO<Self> {
//=--------------------------------------=
if divisor.isZero {
return PVO(self, true)
}
//=--------------------------------------=
if Self.isSigned, divisor == (-1 as Digit), self == Self.min {
return PVO(self, true)
}
//=--------------------------------------=
let qr: QR<Self, Digit> = self.quotientAndRemainder(dividingBy: divisor)
return PVO(qr.quotient, false)
@_disfavoredOverload @_transparent public func dividedReportingOverflow(by divisor: Digit) -> PVO<Self> {
let qro: PVO<QR<Self, Digit>> = self.quotientAndRemainderReportingOverflow(dividingBy: divisor)
return PVO(qro.partialValue.quotient, qro.overflow)
}

@_disfavoredOverload @inlinable public mutating func formRemainderReportingOverflow(dividingBy divisor: Digit) -> Bool {
@_disfavoredOverload @_transparent public mutating func formRemainderReportingOverflow(dividingBy divisor: Digit) -> Bool {
let pvo: PVO<Digit> = self.remainderReportingOverflow(dividingBy: divisor)
self = Self(digit: pvo.partialValue)
return pvo.overflow as Bool
}

@_disfavoredOverload @inlinable public func remainderReportingOverflow(dividingBy divisor: Digit) -> PVO<Digit> {
//=--------------------------------------=
if divisor.isZero {
return PVO(Digit(), true)
}
//=--------------------------------------=
if Self.isSigned, divisor == (-1 as Digit), self == Self.min {
return PVO(Digit(), true)
}
//=--------------------------------------=
let qr: QR<Self, Digit> = self.quotientAndRemainder(dividingBy: divisor)
return PVO(qr.remainder, false)
@_disfavoredOverload @_transparent public func remainderReportingOverflow(dividingBy divisor: Digit) -> PVO<Digit> {
let qro: PVO<QR<Self, Digit>> = self.quotientAndRemainderReportingOverflow(dividingBy: divisor)
return PVO(qro.partialValue.remainder, qro.overflow)
}

//=------------------------------------------------------------------------=
// MARK: Transformations
//=------------------------------------------------------------------------=

@_disfavoredOverload @inlinable public func quotientAndRemainder(dividingBy divisor: Digit) -> QR<Self, Digit> {
@_disfavoredOverload @inlinable public func quotientAndRemainderReportingOverflow(dividingBy divisor: Digit) -> PVO<QR<Self, Digit>> {
let dividendIsLessThanZero: Bool = self.isLessThanZero
let divisorIsLessThanZero: Bool = divisor.isLessThanZero
//=--------------------------------------=
var qr: QR<Magnitude, UInt> = self.magnitude._quotientAndRemainderAsUnsigned(dividingBy: divisor.magnitude)
let qro_ = self.magnitude._quotientAndRemainderReportingOverflowAsUnsigned(dividingBy: divisor.magnitude)
var qro = PVO(QR(Self(bitPattern: qro_.partialValue.quotient), Digit(bitPattern: qro_.partialValue.remainder)), qro_.overflow)
//=--------------------------------------=
if qro.overflow {
assert(divisor.isZero)
assert(qro.partialValue.quotient == self)
assert(qro.partialValue.remainder == Digit())
return qro
}

if dividendIsLessThanZero != divisorIsLessThanZero {
let overflow = qr.quotient._negateReportingOverflowAsSigned()
precondition(!overflow, "quotient overflowed during division")
qro.partialValue.quotient.formTwosComplement()
}

if dividendIsLessThanZero, divisorIsLessThanZero, qro.partialValue.quotient.isLessThanZero {
assert(Self.isSigned && self == Self.min && divisor == -1)
assert(qro.partialValue.quotient == self)
assert(qro.partialValue.remainder == Digit())
qro.overflow = true
return qro
}

if dividendIsLessThanZero {
qr.remainder.formTwosComplement()
qro.partialValue.remainder.formTwosComplement()
}
//=--------------------------------------=
return QR(Self(bitPattern: qr.quotient), Digit(bitPattern: qr.remainder))
return qro as PVO<QR<Self, Digit>>
}
}

Expand All @@ -92,14 +85,17 @@ extension ANKFullWidth where High == High.Magnitude {
// MARK: Transformations
//=------------------------------------------------------------------------=

@inlinable func _quotientAndRemainderAsUnsigned(dividingBy divisor: Digit) -> QR<Self, Digit> {
@inlinable func _quotientAndRemainderReportingOverflowAsUnsigned(dividingBy divisor: Digit) -> PVO<QR<Self, Digit>> {
var quotient = self
let remainder = quotient._formQuotientReportingRemainderAsUnsigned(dividingBy: divisor)
return QR(quotient, remainder)
let remainder = quotient._formQuotientReportingRemainderAndOverflowAsUnsigned(dividingBy: divisor)
return PVO(QR(quotient, remainder.partialValue), remainder.overflow)
}

@inlinable mutating func _formQuotientReportingRemainderAsUnsigned(dividingBy divisor: Digit) -> Digit {
precondition(!divisor.isZero, "division by zero")
@inlinable mutating func _formQuotientReportingRemainderAndOverflowAsUnsigned(dividingBy divisor: Digit) -> PVO<Digit> {
//=--------------------------------------=
if divisor.isZero {
return PVO(UInt(), true)
}
//=--------------------------------------=
var remainder = UInt()
//=--------------------------------------=
Expand All @@ -111,6 +107,6 @@ extension ANKFullWidth where High == High.Magnitude {
}
}
//=--------------------------------------=
return remainder
return PVO(remainder, false)
}
}
Loading

0 comments on commit e6c9130

Please sign in to comment.