diff --git a/Sources/NBKCoreKit/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift b/Sources/NBKCoreKit/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift index 9ed149fe..d7c03da3 100644 --- a/Sources/NBKCoreKit/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift +++ b/Sources/NBKCoreKit/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift @@ -34,64 +34,43 @@ extension NBK.ProperBinaryInteger { extension NBK.ProperBinaryInteger where Integer: NBKSignedInteger { //=------------------------------------------------------------------------= - // MARK: Utilities + // MARK: Utilities x Euclidean Algorithm //=------------------------------------------------------------------------= /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. /// - /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm - /// - /// It extends the Euclidean algorithm and returns some additional values. - /// - /// ### Result - /// - /// ```swift - /// precondition(0 ... T.min.magnitude ~= result) - /// ``` - /// - /// - Note: The GCD of `0` and `0` is `0`. + /// [algorithm]: https://en.wikipedia.org/wiki/euclidean_algorithm /// - /// - Note: The GCD of `0` and `X` is `X`. - /// - /// - Note: The GCD of `Int.min` and `Int.min` is `Int.min.magnitude`. - /// - /// ### Bézout's identity + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm100( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. /// - /// ```swift - /// precondition(T(bitPattern: result) == lhs &* lhsCoefficient &+ rhs &* rhsCoefficient) - /// ``` + /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm /// - /// ### Quotients of dividing by GCD + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm110( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. /// - /// ```swift - /// guard !result.isZero, result <= T.max else { return } - /// precondition(lhsQuotient == lhs / T(result)) - /// precondition(rhsQuotient == rhs / T(result)) - /// ``` + /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm /// - /// ### Iteration + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm101( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. /// - /// ```swift - /// let lhsCoefficientSign = lhs.isLessThanZero != iteration.isOdd - /// let rhsCoefficientSign = rhs.isLessThanZero == iteration.isOdd - /// ``` + /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm /// - @inlinable public static func greatestCommonDivisorByExtendedEuclideanAlgorithm(of lhs: Integer, and rhs: Integer) - -> (result: Integer.Magnitude, lhsCoefficient: Integer, rhsCoefficient: Integer, lhsQuotient: Integer, rhsQuotient: Integer, iteration: Integer.Magnitude) { - //=--------------------------------------= - let lhsIsLessThanZero: Bool = lhs.isLessThanZero - let rhsIsLessThanZero: Bool = rhs.isLessThanZero - //=--------------------------------------= - let unsigned = Magnitude.greatestCommonDivisorByExtendedEuclideanAlgorithm(of: lhs.magnitude, and: rhs.magnitude) - let odd = unsigned.iteration.isOdd as Bool - //=--------------------------------------= - return ( - result: unsigned.result as Integer.Magnitude, - lhsCoefficient: Integer(sign: lhsIsLessThanZero != odd ? .minus : .plus, magnitude: unsigned.lhsCoefficient)!, - rhsCoefficient: Integer(sign: rhsIsLessThanZero == odd ? .minus : .plus, magnitude: unsigned.rhsCoefficient)!, - lhsQuotient: Integer(sign: lhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.lhsQuotient )!, - rhsQuotient: Integer(sign: rhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.rhsQuotient )!, - iteration: unsigned.iteration as Integer.Magnitude) + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm111( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) } } @@ -102,7 +81,7 @@ extension NBK.ProperBinaryInteger where Integer: NBKSignedInteger { extension NBK.ProperBinaryInteger where Integer: NBKUnsignedInteger { //=------------------------------------------------------------------------= - // MARK: Utilities + // MARK: Utilities x Binary Algorithm //=------------------------------------------------------------------------= /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. @@ -137,6 +116,53 @@ extension NBK.ProperBinaryInteger where Integer: NBKUnsignedInteger { return lhs as Integer.Magnitude } + //=------------------------------------------------------------------------= + // MARK: Utilities x Euclidean Algorithm + //=------------------------------------------------------------------------= + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. + /// + /// [algorithm]: https://en.wikipedia.org/wiki/euclidean_algorithm + /// + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm100( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. + /// + /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm + /// + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm110( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. + /// + /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm + /// + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm101( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } + + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. + /// + /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm + /// + @inlinable public static func greatestCommonDivisorByEuclideanAlgorithm111( + of lhs: Integer, and rhs: Integer) -> NBK.GreatestCommonDivisorByEuclideanAlgorithm { + NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs, and: rhs) + } +} + +//*============================================================================* +// MARK: * NBK x Proper Binary Integer x Greatest Common Divisor x E.E.A +//*============================================================================* + +extension NBK { + /// Finds the GCD of `lhs` and `rhs` by using this [algorithm][algorithm]. /// /// [algorithm]: https://en.wikipedia.org/wiki/extended_euclidean_algorithm @@ -178,22 +204,196 @@ extension NBK.ProperBinaryInteger where Integer: NBKUnsignedInteger { /// let rhsCoefficientSign = rhs.isLessThanZero == iteration.isOdd /// ``` /// - @inlinable public static func greatestCommonDivisorByExtendedEuclideanAlgorithm(of lhs: Integer, and rhs: Integer) - -> (result: Integer, lhsCoefficient: Integer, rhsCoefficient: Integer, lhsQuotient: Integer, rhsQuotient: Integer, iteration: Integer) { + @frozen public struct GreatestCommonDivisorByEuclideanAlgorithm where X: NBKBinaryInteger { + + /// The main integer's magnitude type. + public typealias I = X.Magnitude + + //=--------------------------------------------------------------------= + // MARK: State + //=--------------------------------------------------------------------= + + @usableFromInline var i: ((I)) + @usableFromInline var x: (I,I) + @usableFromInline var y: (Y,Y) + @usableFromInline var z: (Z,Z) + + //=--------------------------------------------------------------------= + // MARK: Accessors + //=--------------------------------------------------------------------= + + @inlinable public var iteration: I { + self.i + } + + @inlinable public var result: I { + self.x.0 + } + + @inlinable public var lhsCoefficient: Y { + self.y.0 + } + + @inlinable public var rhsQuotient: Y { + self.y.1 + } + + @inlinable public var rhsCoefficient: Z { + self.z.0 + } + + @inlinable public var lhsQuotient: Z { + self.z.1 + } + } +} +//=----------------------------------------------------------------------------= +// MARK: + Integer, Void, Void +//=----------------------------------------------------------------------------= + +extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == Void, Z == Void { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger { + //=--------------------------------------= + let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs.magnitude, and: rhs.magnitude) + //=--------------------------------------= + self.i = unsigned.i + self.x = unsigned.x + } + + @inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger { + self.i = (00000000) + self.x = (lhs, rhs) + + reduce: while !(self.x.1.isZero) { + self.i += 0001 as X.Digit + self.x.0 %= self.x.1 + Swift.swap(&self.x.0, &self.x.1) + } + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Integer, Integer, Void +//=----------------------------------------------------------------------------= + +extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == X, Z == Void { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger { + //=--------------------------------------= + let lhsIsLessThanZero: Bool = lhs.isLessThanZero + let rhsIsLessThanZero: Bool = rhs.isLessThanZero + //=--------------------------------------= + let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs.magnitude, and: rhs.magnitude) + let odd = unsigned.iteration.isOdd as Bool + //=--------------------------------------= + self.i = unsigned.i + self.x = unsigned.x + //=--------------------------------------= + self.y.0 = Y(sign: lhsIsLessThanZero != odd ? .minus : .plus, magnitude: unsigned.y.0)! + self.y.1 = Y(sign: rhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.y.1)! + } + + @inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger { + self.i = (00000000) + self.x = (lhs, rhs) + self.y = (001, 000) + + reduce: while !self.x.1.isZero { + let division = self.x.0.quotientAndRemainder(dividingBy: self.x.1) + self.i += (000000000000001) as X.Digit + self.x = (self.x.1, division.remainder) + self.y = (self.y.1, division.quotient * self.y.1 + self.y.0) + } + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Integer, Void, Integer +//=----------------------------------------------------------------------------= + +extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == Void, Z == X { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger { + //=--------------------------------------= + let lhsIsLessThanZero: Bool = lhs.isLessThanZero + let rhsIsLessThanZero: Bool = rhs.isLessThanZero //=--------------------------------------= - var (a, b) = (lhs, rhs) as (Integer,Integer) - var (c, d) = (001, 000) as (Integer,Integer) - var (e, f) = (000, 001) as (Integer,Integer) - var iteration = 0000000 as (((((Integer))))) + let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs.magnitude, and: rhs.magnitude) + let odd = unsigned.iteration.isOdd as Bool + //=--------------------------------------= + self.i = unsigned.i + self.x = unsigned.x //=--------------------------------------= - while !b.isZero { - let division = a.quotientAndRemainder(dividingBy: b) - (a, b) = (b, division.remainder) - (c, d) = (d, division.quotient * d + c) - (e, f) = (f, division.quotient * f + e) - iteration += 000000001 as Integer.Digit + self.z.0 = Z(sign: rhsIsLessThanZero == odd ? .minus : .plus, magnitude: unsigned.z.0)! + self.z.1 = Z(sign: lhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.z.1)! + } + + @inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger { + self.i = (00000000) + self.x = (lhs, rhs) + self.z = (000, 001) + + reduce: while !self.x.1.isZero { + let division = self.x.0.quotientAndRemainder(dividingBy: self.x.1) + self.i += (000000000000001) as X.Digit + self.x = (self.x.1, division.remainder) + self.z = (self.z.1, division.quotient * self.z.1 + self.z.0) } + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Integer, Integer, Integer +//=----------------------------------------------------------------------------= + +extension NBK.GreatestCommonDivisorByEuclideanAlgorithm where Y == X, Z == X { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable init(of lhs: X, and rhs: X) where X: NBKSignedInteger { //=--------------------------------------= - return (result: a, lhsCoefficient: c, rhsCoefficient: e, lhsQuotient: f, rhsQuotient: d, iteration: iteration) + let lhsIsLessThanZero: Bool = lhs.isLessThanZero + let rhsIsLessThanZero: Bool = rhs.isLessThanZero + //=--------------------------------------= + let unsigned = NBK.GreatestCommonDivisorByEuclideanAlgorithm(of: lhs.magnitude, and: rhs.magnitude) + let odd = unsigned.iteration.isOdd as Bool + //=--------------------------------------= + self.i = unsigned.i + self.x = unsigned.x + //=--------------------------------------= + self.y.0 = Y(sign: lhsIsLessThanZero != odd ? .minus : .plus, magnitude: unsigned.y.0)! + self.y.1 = Y(sign: rhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.y.1)! + self.z.0 = Z(sign: rhsIsLessThanZero == odd ? .minus : .plus, magnitude: unsigned.z.0)! + self.z.1 = Z(sign: lhsIsLessThanZero /*--*/ ? .minus : .plus, magnitude: unsigned.z.1)! + } + + @inlinable init(of lhs: X, and rhs: X) where X: NBKUnsignedInteger { + self.i = (00000000) + self.x = (lhs, rhs) + self.y = (001, 000) + self.z = (000, 001) + + reduce: while !self.x.1.isZero { + let division = self.x.0.quotientAndRemainder(dividingBy: self.x.1) + self.i += (000000000000001) as X.Digit + self.x = (self.x.1, division.remainder) + self.y = (self.y.1, division.quotient * self.y.1 + self.y.0) + self.z = (self.z.1, division.quotient * self.z.1 + self.z.0) + } } } diff --git a/Tests/NBKCoreKitBenchmarks/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift b/Tests/NBKCoreKitBenchmarks/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift new file mode 100644 index 00000000..181573ae --- /dev/null +++ b/Tests/NBKCoreKitBenchmarks/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift @@ -0,0 +1,136 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +#if !DEBUG + +import NBKCoreKit +import XCTest + +private typealias W = [UInt] +private typealias X = [UInt64] +private typealias Y = [UInt32] + +//*============================================================================* +// MARK: * NBK x Proper Binary Integer x Greatest Common Divisor +//*============================================================================* + +final class NBKProperBinaryIntegerBenchmarksOnGreatestCommonDivisor: XCTestCase { + + typealias T = NBK.PBI + + //=------------------------------------------------------------------------= + // MARK: Tests x Binary Algorithm + //=------------------------------------------------------------------------= + + func testBinaryAlgorithmForAllInt8s() { + for _ in 0 ..< 50 { + for lhs in Int8.min ... Int8.max { + for rhs in Int8.min ... Int8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByBinaryAlgorithm(of: lhs, and: rhs)) + } + } + } + } + + func testBinaryAlgorithmForAllUInt8s() { + for _ in 0 ..< 50 { + for lhs in UInt8.min ... UInt8.max { + for rhs in UInt8.min ... UInt8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByBinaryAlgorithm(of: lhs, and: rhs)) + } + } + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Euclidean Algorithm + //=------------------------------------------------------------------------= + + func testEuclideanAlgorithm100ForAllInt8s() { + for _ in 0 ..< 50 { + for lhs in Int8.min ... Int8.max { + for rhs in Int8.min ... Int8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm100(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm110ForAllInt8s() { + for _ in 0 ..< 50 { + for lhs in Int8.min ... Int8.max { + for rhs in Int8.min ... Int8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm110(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm101ForAllInt8s() { + for _ in 0 ..< 50 { + for lhs in Int8.min ... Int8.max { + for rhs in Int8.min ... Int8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm101(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm111ForAllInt8s() { + for _ in 0 ..< 50 { + for lhs in Int8.min ... Int8.max { + for rhs in Int8.min ... Int8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm111(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm100ForAllUInt8s() { + for _ in 0 ..< 50 { + for lhs in UInt8.min ... UInt8.max { + for rhs in UInt8.min ... UInt8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm100(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm110ForAllUInt8s() { + for _ in 0 ..< 50 { + for lhs in UInt8.min ... UInt8.max { + for rhs in UInt8.min ... UInt8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm110(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm101ForAllUInt8s() { + for _ in 0 ..< 50 { + for lhs in UInt8.min ... UInt8.max { + for rhs in UInt8.min ... UInt8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm101(of: lhs, and: rhs)) + } + } + } + } + + func testEuclideanAlgorithm111ForAllUInt8s() { + for _ in 0 ..< 50 { + for lhs in UInt8.min ... UInt8.max { + for rhs in UInt8.min ... UInt8.max { + NBK.blackHole(NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm111(of: lhs, and: rhs)) + } + } + } + } +} + +#endif diff --git a/Tests/NBKCoreKitTests/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift b/Tests/NBKCoreKitTests/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift index 61623254..8784103e 100644 --- a/Tests/NBKCoreKitTests/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift +++ b/Tests/NBKCoreKitTests/Private/NBKProperBinaryInteger+GreatestCommonDivisor.swift @@ -121,7 +121,7 @@ final class NBKProperBinaryIntegerTestsOnGreatestCommonDivisorByExtendedEuclidea for lhs in Int8.min ... Int8.max { for rhs in Int8.min ... Int8.max { - let extended = NBK.PBI.greatestCommonDivisorByExtendedEuclideanAlgorithm(of: lhs, and: rhs) + let extended = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm111(of: lhs, and: rhs) maxIteration = Swift.max(maxIteration, extended.iteration) XCTAssertEqual(Int8(bitPattern: extended.result), lhs &* extended.lhsCoefficient &+ rhs &* extended.rhsCoefficient) XCTAssertEqual(extended.lhsCoefficient < 0, (extended.lhsCoefficient != 0) && (lhs < 0) != extended.iteration.isOdd) @@ -138,7 +138,7 @@ final class NBKProperBinaryIntegerTestsOnGreatestCommonDivisorByExtendedEuclidea for lhs in UInt8.min ... UInt8.max { for rhs in UInt8.min ... UInt8.max { - let extended = NBK.PBI.greatestCommonDivisorByExtendedEuclideanAlgorithm(of: lhs, and: rhs) + let extended = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm111(of: lhs, and: rhs) maxIteration = Swift.max(maxIteration, extended.iteration) if !extended.iteration.isOdd { @@ -162,9 +162,9 @@ _ lhs: T, _ rhs: T, _ result: T.Magnitude, _ overflow: Bool = false, file: StaticString = #file, line: UInt = #line) { func with(_ lhs: T, _ rhs: T) { - NBKAssertGreatestCommonDivisorByBinaryAlgorithm(/*---------------*/lhs, rhs, result, overflow, file: file, line: line) - NBKAssertGreatestCommonDivisorByExtendedEuclideanAlgorithmAsSigned(lhs, rhs, result, overflow, file: file, line: line) - NBKAssertGreatestCommonDivisorAsUnsigned(lhs.magnitude, rhs.magnitude, /**/ result, /*-----*/ file: file, line: line) + NBKAssertGreatestCommonDivisorByBinaryAlgorithm(/*-------*/lhs, rhs, result, overflow, file: file, line: line) + NBKAssertGreatestCommonDivisorByEuclideanAlgorithmAsSigned(lhs, rhs, result, overflow, file: file, line: line) + NBKAssertGreatestCommonDivisorAsUnsigned(lhs.magnitude, rhs.magnitude, result, /*-----*/ file: file, line: line) } brr: do { @@ -193,8 +193,8 @@ _ lhs: T, _ rhs: T, _ result: T.Magnitude, file: StaticString = #file, line: UInt = #line) { func with(_ lhs: T, _ rhs: T) { - NBKAssertGreatestCommonDivisorByBinaryAlgorithm(lhs, rhs, result, false, file: file, line: line) - NBKAssertGreatestCommonDivisorByExtendedEuclideanAlgorithmAsUnsigned(lhs, rhs, result, file: file, line: line) + NBKAssertGreatestCommonDivisorByBinaryAlgorithm(lhs, rhs, result, false, file: file, line: line) + NBKAssertGreatestCommonDivisorByEuclideanAlgorithmAsUnsigned(lhs, rhs, result, file: file, line: line) } with(0 + lhs, 0 + rhs) @@ -215,65 +215,93 @@ file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(T.isSigned && binary == T.min.magnitude, overflow, file: file, line: line) } -private func NBKAssertGreatestCommonDivisorByExtendedEuclideanAlgorithmAsSigned( +private func NBKAssertGreatestCommonDivisorByEuclideanAlgorithmAsSigned( _ lhs: T, _ rhs: T, _ result: T.Magnitude, _ overflow: Bool, file: StaticString = #file, line: UInt = #line) { //=------------------------------------------= - let extended = NBK.PBI.greatestCommonDivisorByExtendedEuclideanAlgorithm(of: lhs, and: rhs) + let e100 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm100(of: lhs, and: rhs) + let e110 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm110(of: lhs, and: rhs) + let e101 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm101(of: lhs, and: rhs) + let e111 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm111(of: lhs, and: rhs) //=------------------------------------------= - XCTAssertEqual(extended.result, result, file: file, line: line) - XCTAssertEqual(extended.result == T.min.magnitude, overflow, file: file, line: line) - XCTAssertEqual(lhs &* extended.lhsCoefficient &+ rhs &* extended.rhsCoefficient, T(bitPattern: result), file: file, line: line) + XCTAssertEqual(e111.result, result, file: file, line: line) + XCTAssertEqual(e111.result == T.min.magnitude, overflow, file: file, line: line) + XCTAssertEqual(lhs &* e111.lhsCoefficient &+ rhs &* e111.rhsCoefficient, T(bitPattern: result), file: file, line: line) if result == T.min.magnitude { let values = [lhs, rhs] XCTAssert(1 <= values.filter({ $0 == T.min }).count, file: file, line: line) - XCTAssert(2 == values.filter({ $0 == T.min }).count + values.filter(\.isZero).count, file: file, line: line) + XCTAssert(2 == values.filter({ $0 == T.min }).count + values.filter(\.isZero).count, file: file, line: line) - XCTAssertEqual(lhs == T.min && rhs != T.min ? -1 : 0, extended.lhsCoefficient, file: file, line: line) - XCTAssertEqual(rhs == T.min /*-----------*/ ? -1 : 0, extended.rhsCoefficient, file: file, line: line) - XCTAssertEqual(lhs == T.min /*-----------*/ ? -1 : 0, extended.lhsQuotient, file: file, line: line) - XCTAssertEqual(rhs == T.min /*-----------*/ ? -1 : 0, extended.rhsQuotient, file: file, line: line) + XCTAssertEqual(lhs == T.min && rhs != T.min ? -1 : 0, e111.lhsCoefficient, file: file, line: line) + XCTAssertEqual(rhs == T.min /*-----------*/ ? -1 : 0, e111.rhsCoefficient, file: file, line: line) + XCTAssertEqual(lhs == T.min /*-----------*/ ? -1 : 0, e111.lhsQuotient, file: file, line: line) + XCTAssertEqual(rhs == T.min /*-----------*/ ? -1 : 0, e111.rhsQuotient, file: file, line: line) } else if result.isZero { XCTAssertEqual(0, lhs, file: file, line: line) XCTAssertEqual(0, rhs, file: file, line: line) - XCTAssertEqual(1, extended.lhsCoefficient, file: file, line: line) - XCTAssertEqual(0, extended.rhsCoefficient, file: file, line: line) - XCTAssertEqual(1, extended.lhsQuotient, file: file, line: line) - XCTAssertEqual(0, extended.rhsQuotient, file: file, line: line) + XCTAssertEqual(1, e111.lhsCoefficient, file: file, line: line) + XCTAssertEqual(0, e111.rhsCoefficient, file: file, line: line) + XCTAssertEqual(1, e111.lhsQuotient, file: file, line: line) + XCTAssertEqual(0, e111.rhsQuotient, file: file, line: line) } else { - XCTAssertEqual(extended.lhsQuotient, lhs / T(result), file: file, line: line) - XCTAssertEqual(extended.rhsQuotient, rhs / T(result), file: file, line: line) + XCTAssertEqual(e111.lhsQuotient, lhs / T(result), file: file, line: line) + XCTAssertEqual(e111.rhsQuotient, rhs / T(result), file: file, line: line) } + //=------------------------------------------= + XCTAssertEqual(e111.iteration, e100.iteration, file: file, line: line) + XCTAssertEqual(e111.result, e100.result, file: file, line: line) + XCTAssertEqual(e111.iteration, e110.iteration, file: file, line: line) + XCTAssertEqual(e111.result, e110.result, file: file, line: line) + XCTAssertEqual(e111.lhsCoefficient, e110.lhsCoefficient, file: file, line: line) + XCTAssertEqual(e111.rhsQuotient, e110.rhsQuotient, file: file, line: line) + XCTAssertEqual(e111.iteration, e101.iteration, file: file, line: line) + XCTAssertEqual(e111.result, e101.result, file: file, line: line) + XCTAssertEqual(e111.rhsCoefficient, e101.rhsCoefficient, file: file, line: line) + XCTAssertEqual(e111.lhsQuotient, e101.lhsQuotient, file: file, line: line) } -private func NBKAssertGreatestCommonDivisorByExtendedEuclideanAlgorithmAsUnsigned( +private func NBKAssertGreatestCommonDivisorByEuclideanAlgorithmAsUnsigned( _ lhs: T, _ rhs: T, _ result: T.Magnitude, file: StaticString = #file, line: UInt = #line) { //=------------------------------------------= - let extended = NBK.PBI.greatestCommonDivisorByExtendedEuclideanAlgorithm(of: lhs, and: rhs) + let e100 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm100(of: lhs, and: rhs) + let e110 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm110(of: lhs, and: rhs) + let e101 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm101(of: lhs, and: rhs) + let e111 = NBK.PBI.greatestCommonDivisorByEuclideanAlgorithm111(of: lhs, and: rhs) //=------------------------------------------= - XCTAssertEqual(extended.result, T(result), file: file, line: line) + XCTAssertEqual(e111.result, T(result), file: file, line: line) if !result.isZero { - XCTAssertEqual(extended.lhsQuotient, lhs / T(result), file: file, line: line) - XCTAssertEqual(extended.rhsQuotient, rhs / T(result), file: file, line: line) + XCTAssertEqual(e111.lhsQuotient, lhs / T(result), file: file, line: line) + XCTAssertEqual(e111.rhsQuotient, rhs / T(result), file: file, line: line) } else { XCTAssertEqual(0, lhs, file: file, line: line) XCTAssertEqual(0, rhs, file: file, line: line) - XCTAssertEqual(1, extended.lhsQuotient, file: file, line: line) - XCTAssertEqual(0, extended.rhsQuotient, file: file, line: line) - XCTAssertEqual(1, extended.lhsCoefficient, file: file, line: line) - XCTAssertEqual(0, extended.rhsCoefficient, file: file, line: line) + XCTAssertEqual(1, e111.lhsQuotient, file: file, line: line) + XCTAssertEqual(0, e111.rhsQuotient, file: file, line: line) + XCTAssertEqual(1, e111.lhsCoefficient, file: file, line: line) + XCTAssertEqual(0, e111.rhsCoefficient, file: file, line: line) } - if !extended.iteration.isOdd { - XCTAssertEqual(result, lhs &* extended.lhsCoefficient &- rhs &* extended.rhsCoefficient, file: file, line: line) + if !e111.iteration.isOdd { + XCTAssertEqual(result, lhs &* e111.lhsCoefficient &- rhs &* e111.rhsCoefficient, file: file, line: line) } else { - XCTAssertEqual(result, rhs &* extended.rhsCoefficient &- lhs &* extended.lhsCoefficient, file: file, line: line) + XCTAssertEqual(result, rhs &* e111.rhsCoefficient &- lhs &* e111.lhsCoefficient, file: file, line: line) } + //=------------------------------------------= + XCTAssertEqual(e111.iteration, e100.iteration, file: file, line: line) + XCTAssertEqual(e111.result, e100.result, file: file, line: line) + XCTAssertEqual(e111.iteration, e110.iteration, file: file, line: line) + XCTAssertEqual(e111.result, e110.result, file: file, line: line) + XCTAssertEqual(e111.lhsCoefficient, e110.lhsCoefficient, file: file, line: line) + XCTAssertEqual(e111.rhsQuotient, e110.rhsQuotient, file: file, line: line) + XCTAssertEqual(e111.iteration, e101.iteration, file: file, line: line) + XCTAssertEqual(e111.result, e101.result, file: file, line: line) + XCTAssertEqual(e111.rhsCoefficient, e101.rhsCoefficient, file: file, line: line) + XCTAssertEqual(e111.lhsQuotient, e101.lhsQuotient, file: file, line: line) } #endif