//=----------------------------------------------------------------------------= // This source file is part of the AwesomeNumbersKit open source project. // // Copyright (c) 2022 Oscar Byström Ericsson // Licensed under Apache License, Version 2.0 // // See http://www.apache.org/licenses/LICENSE-2.0 for license information. //=----------------------------------------------------------------------------= //*============================================================================* // MARK: * ANK x Core Integer //*============================================================================* /// A fixed-width, binary, integer that is up to 64 bits wide. /// /// Only the following types in the standard library may conform to this protocol: /// /// - `Int` /// - `Int8` /// - `Int16` /// - `Int32` /// - `Int64` /// /// - `UInt` /// - `UInt8` /// - `UInt16` /// - `UInt32` /// - `UInt64` /// public protocol ANKCoreInteger: ANKFixedWidthInteger where BitPattern == Magnitude, Digit == Self, Magnitude: ANKCoreInteger { } //=----------------------------------------------------------------------------= // MARK: + Details //=----------------------------------------------------------------------------= extension ANKCoreInteger { //=------------------------------------------------------------------------= // MARK: Details x Bit Pattern //=------------------------------------------------------------------------= @inlinable public init(bitPattern: BitPattern) { self = Swift.unsafeBitCast(bitPattern, to: Self.self) } @inlinable public var bitPattern: BitPattern { Swift.unsafeBitCast(self, to: BitPattern.self) } //=------------------------------------------------------------------------= // MARK: Details x Two's Complement //=------------------------------------------------------------------------= @inlinable public mutating func formTwosComplementSubsequence(_ carry: Bool) -> Bool { let pvo: PVO = self.twosComplementSubsequence(carry) self = pvo.partialValue return pvo.overflow as Bool } @inlinable public func twosComplementSubsequence(_ carry: Bool) -> PVO { var partialValue = ~self let overflow: Bool = carry && partialValue.addReportingOverflow(1 as Self) return PVO(partialValue, overflow) } //=------------------------------------------------------------------------= // MARK: Details x Addition, Subtraction, Multiplication, Division //=------------------------------------------------------------------------= @inlinable public mutating func addReportingOverflow(_ other: Self) -> Bool { let pvo: PVO = self.addingReportingOverflow(other) self = pvo.partialValue return pvo.overflow as Bool } @inlinable public mutating func subtractReportingOverflow(_ other: Self) -> Bool { let pvo: PVO = self.subtractingReportingOverflow(other) self = pvo.partialValue return pvo.overflow as Bool } @inlinable public mutating func multiplyReportingOverflow(by other: Self) -> Bool { let pvo: PVO = self.multipliedReportingOverflow(by: other) self = pvo.partialValue return pvo.overflow as Bool } @inlinable public mutating func multiplyFullWidth(by other: Self) -> Self { let product: HL = self.multipliedFullWidth(by: other) self = Self(bitPattern: product.low) return product.high as Self } @inlinable public mutating func divideReportingOverflow(by other: Self) -> Bool { let pvo: PVO = self.dividedReportingOverflow(by: other) self = pvo.partialValue return pvo.overflow as Bool } @inlinable public mutating func formRemainderReportingOverflow(dividingBy other: Self) -> Bool { let pvo: PVO = self.remainderReportingOverflow(dividingBy: other) self = pvo.partialValue return pvo.overflow as Bool } @inlinable public func quotientAndRemainderReportingOverflow(dividingBy other: Self) -> PVO> { let quotient: PVO = self.dividedReportingOverflow(by: other) let remainder: PVO = self.remainderReportingOverflow(dividingBy: other) assert(quotient.overflow == remainder.overflow) return PVO(QR(quotient.partialValue, remainder.partialValue), quotient.overflow) } //=------------------------------------------------------------------------= // MARK: Division x Full Width //=------------------------------------------------------------------------= @inlinable public func dividingFullWidthReportingOverflow(_ other: HL) -> PVO> where Self: ANKSignedInteger { let lhsIsLessThanZero: Bool = other.high.isLessThanZero let rhsIsLessThanZero: Bool = /*--*/self.isLessThanZero let minus: Bool = lhsIsLessThanZero != rhsIsLessThanZero //=--------------------------------------= var lhsMagnitude = ANK.bitCast(other) as HL if lhsIsLessThanZero { var carry = true carry = lhsMagnitude.low .formTwosComplementSubsequence(carry) carry = lhsMagnitude.high.formTwosComplementSubsequence(carry) } let rhsMagnitude = self.magnitude as Magnitude //=--------------------------------------= var qro = ANK.bitCast(rhsMagnitude.dividingFullWidthReportingOverflow(lhsMagnitude)) as PVO> //=--------------------------------------= if minus { qro.partialValue.quotient.formTwosComplement() } if lhsIsLessThanZero { qro.partialValue.remainder.formTwosComplement() } if minus != qro.partialValue.quotient.isLessThanZero { qro.overflow = qro.overflow || !(minus && qro.partialValue.quotient.isZero) } //=--------------------------------------= return qro as PVO> } @inlinable public func dividingFullWidthReportingOverflow(_ other: HL) -> PVO> where Self: ANKUnsignedInteger { //=--------------------------------------= // divisor is zero //=--------------------------------------= if self.isZero { return ANK.bitCast(PVO(QR(other.low, other.low), true)) } //=--------------------------------------= // quotient does not fit in two halves //=--------------------------------------= if self <= other.high { return PVO(self.dividingFullWidth(HL(other.high % self, other.low)), true) // stdlib } //=--------------------------------------= return PVO(self.dividingFullWidth(other), false) // stdlib } } //*============================================================================* // MARK: * ANK x Core Integer x Swift //*============================================================================* extension Int: ANKCoreInteger, ANKSignedInteger { public typealias BitPattern = Magnitude } extension Int8: ANKCoreInteger, ANKSignedInteger { public typealias BitPattern = Magnitude } extension Int16: ANKCoreInteger, ANKSignedInteger { public typealias BitPattern = Magnitude } extension Int32: ANKCoreInteger, ANKSignedInteger { public typealias BitPattern = Magnitude } extension Int64: ANKCoreInteger, ANKSignedInteger { public typealias BitPattern = Magnitude } extension UInt: ANKCoreInteger, ANKUnsignedInteger { public typealias BitPattern = Magnitude } extension UInt8: ANKCoreInteger, ANKUnsignedInteger { public typealias BitPattern = Magnitude } extension UInt16: ANKCoreInteger, ANKUnsignedInteger { public typealias BitPattern = Magnitude } extension UInt32: ANKCoreInteger, ANKUnsignedInteger { public typealias BitPattern = Magnitude } extension UInt64: ANKCoreInteger, ANKUnsignedInteger { public typealias BitPattern = Magnitude }