From 014869bda947f440e5a8d90a051f7f07a17b4f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Bystr=C3=B6m=20Ericsson?= Date: Wed, 8 Nov 2023 10:26:44 +0100 Subject: [PATCH] [NBKCoreKit] Cleanup and some long division stuff. --- .../NBKIntegerDescription+RadixSolution.swift | 6 +- ...trictUnsignedInteger+Division+Digit.swift} | 87 +---------- ...KStrictUnsignedInteger+Division+Long.swift | 142 ++++++++++++++++++ 3 files changed, 149 insertions(+), 86 deletions(-) rename Sources/NBKCoreKit/Private/{NBKStrictUnsignedInteger+Division.swift => NBKStrictUnsignedInteger+Division+Digit.swift} (53%) create mode 100644 Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Long.swift diff --git a/Sources/NBKCoreKit/Private/NBKIntegerDescription+RadixSolution.swift b/Sources/NBKCoreKit/Private/NBKIntegerDescription+RadixSolution.swift index 87bc7a71..9dd934b9 100644 --- a/Sources/NBKCoreKit/Private/NBKIntegerDescription+RadixSolution.swift +++ b/Sources/NBKCoreKit/Private/NBKIntegerDescription+RadixSolution.swift @@ -298,11 +298,11 @@ extension NBK.IntegerDescription { //=----------------------------------= precondition(base.value > 1) //=----------------------------------= + var exponentiation = Exponentiation(1, base.value) + //=----------------------------------= // radix: 003, 005, 006, 007, ... //=----------------------------------= - var exponentiation = Exponentiation(1, base.value) - let capacity: Int = Element.bitWidth.trailingZeroBitCount - 1 - Swift.withUnsafeTemporaryAllocation(of: Exponentiation.self, capacity: capacity) { + Swift.withUnsafeTemporaryAllocation(of: Exponentiation.self, capacity: Element.bitWidth.trailingZeroBitCount - 1) { let squares = NBK.unwrapping($0)! var pointer = squares.baseAddress //=------------------------------= diff --git a/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division.swift b/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Digit.swift similarity index 53% rename from Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division.swift rename to Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Digit.swift index 8344b8dd..91c3ea08 100644 --- a/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division.swift +++ b/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Digit.swift @@ -8,87 +8,8 @@ //=----------------------------------------------------------------------------= //*============================================================================* -// MARK: * NBK x Strict Unsigned Integer x Division +// MARK: * NBK x Strict Unsigned Integer x Division x Digit x Sub Sequence //*============================================================================* -//=----------------------------------------------------------------------------= -// MARK: + Long Division Algorithms -//=----------------------------------------------------------------------------= - -extension NBK.StrictUnsignedInteger where Base: MutableCollection { - - //=------------------------------------------------------------------------= - // MARK: Transformations - //=------------------------------------------------------------------------= - - /// Forms the `remainder` of dividing the `dividend` by the `divisor`, - /// then returns the `quotient`. Its arguments must match the arguments - /// of one long division iteration. - /// - /// - Parameters: - /// - dividend: The current iteration's `remainder` slice from the `quotient` - /// element's index. It must be exactly one element wider than the `divisor`. - /// - /// - divisor: The normalized `divisor`. Its last element's most significant - /// bit must be set to ensure that the initial `quotient` approximation does - /// not exceed the real `quotient` by more than 2. - /// - /// ## Example Usage in Long Division Algorithm - /// - /// ```swift - /// // try fast path - /// // normalization - /// - /// var quotient = uninitialized(remainder.count - divisor.count) { quotient in - /// for index in quotient.indices.reversed() { - /// let digit = formRemainderWithQuotientLong2111MSBUnchecked( - /// dividing: &remainder[index ..< index + divisor.count + 1], by: divisor) - /// quotient.baseAddress!.advanced(by: index).initialize(to: digit) - /// } - /// } - /// - /// // normalization - /// // return values - /// ``` - /// - @inlinable public static func formRemainderWithQuotientLong2111MSBUnchecked( - dividing dividend: inout Base, by divisor: some RandomAccessCollection) -> Base.Element { - //=--------------------------------------= - Swift.assert(divisor.last!.mostSignificantBit, - "the divisor must be normalized") - - Swift.assert(dividend.count == divisor.count + 1, - "the dividend must be exactly one element wider than the divisor") - - Swift.assert(NBK.SUISS.compare(dividend.dropFirst(), to: divisor).isLessThanZero, - "the quotient of each iteration must fit in one element") - //=--------------------------------------= - let numerator = NBK.TBI.suffix2(dividend) - let denominator = NBK.TBI.suffix1(divisor ) - //=--------------------------------------= - var quotient: Base.Element = denominator == numerator.high - ? Base.Element.max // the quotient must fit in one element - : denominator.dividingFullWidth(numerator).quotient/*---*/ - //=--------------------------------------= - if quotient.isZero { return quotient } - //=--------------------------------------= - var overflow = (NBK).SUISS.decrementInIntersection(÷nd, by: divisor, times: quotient).overflow - - decrementQuotientAtMostTwice: while overflow { - quotient = quotient &- 1 as Base.Element - overflow = !NBK .SUISS.increment(÷nd, by: divisor).overflow - } - - Swift.assert(NBK.SUISS.compare(dividend, to: divisor).isLessThanZero) - return quotient as Base.Element - } -} - -//*============================================================================* -// MARK: * NBK x Strict Unsigned Integer x Division x Sub Sequence -//*============================================================================* -//=----------------------------------------------------------------------------= -// MARK: + Digit -//=----------------------------------------------------------------------------= extension NBK.StrictUnsignedInteger.SubSequence { @@ -113,7 +34,7 @@ extension NBK.StrictUnsignedInteger.SubSequence { } //=------------------------------------------------------------------------= - // MARK: Transformations x With Non Zero Divisor + // MARK: Transformations x Non Zero Divisor //=------------------------------------------------------------------------= /// Returns the `remainder` of dividing the `base` by the `divisor`. @@ -133,7 +54,7 @@ extension NBK.StrictUnsignedInteger.SubSequence { } //=----------------------------------------------------------------------------= -// MARK: + Digit where Base is Mutable Collection +// MARK: + where Base is Mutable Collection //=----------------------------------------------------------------------------= extension NBK.StrictUnsignedInteger.SubSequence where Base: MutableCollection { @@ -159,7 +80,7 @@ extension NBK.StrictUnsignedInteger.SubSequence where Base: MutableCollection { } //=------------------------------------------------------------------------= - // MARK: Transformations x where Divisor is Non Zero + // MARK: Transformations x Non Zero Divisor //=------------------------------------------------------------------------= /// Forms the `quotient` of dividing the `base` by the `divisor`, and returns the `remainder`. diff --git a/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Long.swift b/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Long.swift new file mode 100644 index 00000000..0f9bf0fa --- /dev/null +++ b/Sources/NBKCoreKit/Private/NBKStrictUnsignedInteger+Division+Long.swift @@ -0,0 +1,142 @@ +//=----------------------------------------------------------------------------= +// This source file is part of the Numberick open source project. +// +// Copyright (c) 2023 Oscar Byström Ericsson +// Licensed under Apache License, Version 2.0 +// +// See http://www.apache.org/licenses/LICENSE-2.0 for license information. +//=----------------------------------------------------------------------------= + +//*============================================================================* +// MARK: * NBK x Strict Unsigned Integer x Division x Long +//*============================================================================* +//=----------------------------------------------------------------------------= +// MARK: + where Base is Unsafe Buffer Pointer +//=----------------------------------------------------------------------------= + +extension NBK.StrictUnsignedInteger where Base: MutableCollection { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + /// Initializes `base` to the [long][algorithm] `quotient` of dividing the + /// `dividend` by the `divisor` and forms the `remainder` in the `dividend`. + /// + /// - Parameter base: A nonempty buffer of size `dividend.count - divisor.count`. + /// + /// - Parameter dividend: The normalized `dividend`. It must be wider than + /// the `divisor` and less than `divisor << (Element.bitWidth * base.count)` + /// to ensure that the `quotient` fits. + /// + /// - Parameter divisor: The normalized `divisor`. Its last element's most significant + /// bit must be set to ensure that the initial `quotient` element approximation does + /// not exceed the real `quotient` by more than 2. + /// + /// - Important: The `base` must be uninitialized, or its elements must be trivial. + /// + /// [algorithm]: https://en.wikipedia.org/wiki/long_division + /// + /// ## Example Usage in Long Division Algorithm + /// + /// ```swift + /// // try fast path + /// // normalization + /// + /// var quotient = uninitialized(remainder.count - divisor.count) { + /// initializeToQuotientFormRemainderByLongAlgorithm2111MSB(&$0, dividing: ÷nd, by: divisor) + /// } + /// + /// // normalization + /// // return values + /// ``` + /// + @inlinable public static func initializeToQuotientFormRemainderByLongAlgorithm2111MSB( + _ base: inout Base, dividing dividend: inout Base, by divisor: UnsafeBufferPointer) + where Base == UnsafeMutableBufferPointer { + //=--------------------------------------= + Swift.assert(base.count >= 1 && base.count == dividend.count - divisor.count, + "the dividend must be wider than the divisor") + + Swift.assert(NBK.SUISS.compare(dividend.dropFirst(base.count), to: divisor).isLessThanZero, + "the quotient must fit in dividend.count - divisor.count elements") + //=--------------------------------------= + for index in base.indices.reversed() { + let digit = NBK.SUI.formRemainderWithQuotientByOneLongIteration2111MSB( + dividing: ÷nd[index ..< index &+ divisor.count &+ 1], by: divisor) + base.baseAddress!.advanced(by: index).initialize(to: digit) + } + } +} + +//=----------------------------------------------------------------------------= +// MARK: + where Base is Mutable Collection +//=----------------------------------------------------------------------------= + +extension NBK.StrictUnsignedInteger where Base: MutableCollection { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + /// Forms the `remainder` of dividing the `dividend` by the `divisor`, + /// then returns the `quotient`. Its arguments must match the arguments + /// of one long division iteration. + /// + /// - Parameter dividend: The current iteration's `remainder` slice from the `quotient` + /// element's index. It must be exactly one element wider than the `divisor`. + /// + /// - Parameter divisor: The normalized `divisor`. Its last element's most significant + /// bit must be set to ensure that the initial `quotient` element approximation does + /// not exceed the real `quotient` by more than 2. + /// + /// ## Example Usage in Long Division Algorithm + /// + /// ```swift + /// // try fast path + /// // normalization + /// + /// var quotient = uninitialized(dividend.count - divisor.count) { + /// for index in $0.indices.reversed() { + /// let digit = formRemainderWithQuotientByOneLongIteration2111MSB( + /// dividing: ÷nd[index ..< index &+ divisor.count &+ 1], by: divisor) + /// $0.baseAddress!.advanced(by: index).initialize(to: digit) + /// } + /// } + /// + /// // normalization + /// // return values + /// ``` + /// + @inlinable public static func formRemainderWithQuotientByOneLongIteration2111MSB( + dividing dividend: inout Base, by divisor: some RandomAccessCollection) -> Base.Element { + //=--------------------------------------= + Swift.assert(divisor.last!.mostSignificantBit, + "the divisor must be normalized") + + Swift.assert(dividend.count == divisor.count + 1, + "the dividend must be exactly one element wider than the divisor") + + Swift.assert(NBK.SUISS.compare(dividend.dropFirst(), to: divisor).isLessThanZero, + "the quotient of each iteration must fit in one element") + //=--------------------------------------= + let numerator = NBK.TBI.suffix2(dividend) + let denominator = NBK.TBI.suffix1(divisor ) + //=--------------------------------------= + var quotient: Base.Element = denominator == numerator.high + ? Base.Element.max // the quotient must fit in one element + : denominator.dividingFullWidth((((numerator)))) .quotient + //=--------------------------------------= + if quotient.isZero { return quotient } + //=--------------------------------------= + var overflow = (NBK).SUISS.decrementInIntersection(÷nd, by: divisor, times: quotient).overflow + + decrementQuotientAtMostTwice: while overflow { + quotient = quotient &- 1 as Base.Element + overflow = !NBK .SUISS.increment(÷nd, by: divisor).overflow + } + + Swift.assert(NBK.SUISS.compare(dividend, to: divisor).isLessThanZero) + return quotient as Base.Element + } +}