diff --git a/.swiftpm/NBKFlexibleWidthKit-Benchmarks.xctestplan b/.swiftpm/NBKFlexibleWidthKit-Benchmarks.xctestplan new file mode 100644 index 00000000..6e96461d --- /dev/null +++ b/.swiftpm/NBKFlexibleWidthKit-Benchmarks.xctestplan @@ -0,0 +1,34 @@ +{ + "configurations" : [ + { + "id" : "2BBD9A51-D890-4B97-AED4-B9962867DF57", + "name" : "Main", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : false + }, + "testTargets" : [ + { + "skippedTests" : [ + "NBKFibonacciXLBenchmarks\/testNoLoop10000000()", + "NBKFlexibleWidthBenchmarksOnExponentiationAsUIntXL\/test7RaisedToPrime777()", + "NBKFlexibleWidthBenchmarksOnExponentiationAsUIntXL\/testNoLoop5RaisedToPrime22222()", + "NBKFlexibleWidthBenchmarksOnExponentiationAsUIntXL\/testNoLoop5RaisedToPrime33333()", + "NBKFlexibleWidthBenchmarksOnExponentiationAsUIntXL\/testNoLoop5RaisedToPrime55555()", + "NBKFlexibleWidthBenchmarksOnExponentiationAsUIntXL\/testNoLoop7RaisedToPrime77777()", + "NBKFlexibleWidthBenchmarksOnTextAsUIntXL\/testEncodingUsingSwiftStdlibRadix10()", + "NBKFlexibleWidthBenchmarksOnTextAsUIntXL\/testEncodingUsingSwiftStdlibRadix16()" + ], + "target" : { + "containerPath" : "container:", + "identifier" : "NBKFlexibleWidthKitBenchmarks", + "name" : "NBKFlexibleWidthKitBenchmarks" + } + } + ], + "version" : 1 +} diff --git a/.swiftpm/NBKFlexibleWidthKit.xctestplan b/.swiftpm/NBKFlexibleWidthKit.xctestplan new file mode 100644 index 00000000..de7211dc --- /dev/null +++ b/.swiftpm/NBKFlexibleWidthKit.xctestplan @@ -0,0 +1,32 @@ +{ + "configurations" : [ + { + "id" : "6FC9897F-2BF3-4836-8372-787CE5195F87", + "name" : "Main", + "options" : { + + } + } + ], + "defaultOptions" : { + "codeCoverage" : { + "targets" : [ + { + "containerPath" : "container:", + "identifier" : "NBKFlexibleWidthKit", + "name" : "NBKFlexibleWidthKit" + } + ] + } + }, + "testTargets" : [ + { + "target" : { + "containerPath" : "container:", + "identifier" : "NBKFlexibleWidthKitTests", + "name" : "NBKFlexibleWidthKitTests" + } + } + ], + "version" : 1 +} diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/NBKFlexibleWidthKit-Benchmarks.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/NBKFlexibleWidthKit-Benchmarks.xcscheme new file mode 100644 index 00000000..c12d963f --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/NBKFlexibleWidthKit-Benchmarks.xcscheme @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/NBKFlexibleWidthKit.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/NBKFlexibleWidthKit.xcscheme new file mode 100644 index 00000000..c72f5e4d --- /dev/null +++ b/.swiftpm/xcode/xcshareddata/xcschemes/NBKFlexibleWidthKit.xcscheme @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Package.swift b/Package.swift index 7fcb06eb..7878ac37 100644 --- a/Package.swift +++ b/Package.swift @@ -48,6 +48,12 @@ let package = Package( .library( name: "NBKDoubleWidthKit", targets: ["NBKDoubleWidthKit"]), + //=--------------------------------------= + // NBK x Flexible Width Kit + //=--------------------------------------= + .library( + name: "NBKFlexibleWidthKit", + targets: ["NBKFlexibleWidthKit"]), ], targets: [ //=--------------------------------------= @@ -84,6 +90,20 @@ let package = Package( .testTarget( name: "NBKDoubleWidthKitTests", dependencies: ["NBKDoubleWidthKit"]), + //=--------------------------------------= + // NBK x Flexible Width Kit + //=--------------------------------------= + .target( + name: "NBKFlexibleWidthKit", + dependencies: ["NBKCoreKit"]), + + .testTarget( + name: "NBKFlexibleWidthKitBenchmarks", + dependencies: ["NBKFlexibleWidthKit"]), + + .testTarget( + name: "NBKFlexibleWidthKitTests", + dependencies: ["NBKFlexibleWidthKit"]), ] ) diff --git a/README.md b/README.md index 70d92b47..7a93f3ef 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ * [NBKCoreKit](#nbkcorekit) * [NBKDoubleWidthKit](#nbkdoublewidthkit) +* [NBKFlexibleWidthKit](#nbkflexiblewidthkit) * [Installation](#installation) * [Acknowledgements](#acknowledgements) @@ -113,6 +114,43 @@ Int256(5) % Int(5), UInt256(5) % UInt(5) > [!NOTE] > You can use `StaticString` until `StaticBigInt` becomes available. + + +## [NBKFlexibleWidthKit][FLX/D] ([Sources][FLX/S], [Tests][FLX/T], [Benchmarks][FLX/B]) + +> [!IMPORTANT] +> It's a work in progress. I may rework it at any time. + +### Models + +- [NBKFibonacciXL](Sources/NBKFlexibleWidthKit/Models/NBKFibonacciXL.swift) +- [UIntXL](Sources/NBKFlexibleWidthKit/Models/NBKFlexibleWidth.swift) + +### Fibonacci + +```swift +NBKFibonacciXL(0) // (index: 0, element: 0, next: 1) +NBKFibonacciXL(1) // (index: 1, element: 1, next: 1) +NBKFibonacciXL(2) // (index: 2, element: 1, next: 2) +NBKFibonacciXL(3) // (index: 3, element: 2, next: 3) +NBKFibonacciXL(4) // (index: 4, element: 3, next: 5) +NBKFibonacciXL(5) // (index: 5, element: 5, next: 8) +``` + +It uses a fast double-and-add algorithm: + +```swift +NBKFibonacciXL(10_000_000) // 2.3s on M1 MacBook Pro +``` + +But you can also step through it manually: + +```swift +public mutating func increment() { ... } // index + 1 +public mutating func decrement() { ... } // index - 1 +public mutating func double() { ... } // index * 2 +``` + ## Installation @@ -138,9 +176,10 @@ Add this package to your list of package dependencies. Choose target dependencies from the products in [Package.swift](Package.swift). ```swift -.product(name: "Numberick", package: "Numberick"), -.product(name: "NBKCoreKit", package: "Numberick"), -.product(name: "NBKDoubleWidthKit", package: "Numberick"), +.product(name: "Numberick", package: "Numberick"), +.product(name: "NBKCoreKit", package: "Numberick"), +.product(name: "NBKDoubleWidthKit", package: "Numberick"), +.product(name: "NBKFlexibleWidthKit", package: "Numberick"), ``` ### Using [CocoaPods](http://cocoapods.org) @@ -163,15 +202,20 @@ This project is inspired by [**Int128**][Apple/Int128] and [**DoubleWidth**][App [NBK/D]: https://oscbyspro.github.io/Numberick/documentation/numberick [DBL/D]: https://oscbyspro.github.io/Numberick/documentation/numberick/nbkdoublewidth +[FLX/D]: https://oscbyspro.github.io/Numberick/documentation/numberick/nbkflexiblewidth +[SIG/D]: https://oscbyspro.github.io/Numberick/documentation/numberick/nbksigned [COR/S]: Sources/NBKCoreKit [DBL/S]: Sources/NBKDoubleWidthKit +[FLX/S]: Sources/NBKFlexibleWidthKit [COR/T]: Tests/NBKCoreKitTests [DBL/T]: Tests/NBKDoubleWidthKitTests +[FLX/T]: Tests/NBKFlexibleWidthKitTests [COR/B]: Tests/NBKCoreKitBenchmarks [DBL/B]: Tests/NBKDoubleWidthKitBenchmarks +[FLX/B]: Tests/NBKFlexibleWidthKitBenchmarks diff --git a/Sources/NBKCoreKit/Models/NBKPrimeSieve.swift b/Sources/NBKCoreKit/Models/NBKPrimeSieve.swift index eb0d750d..28f16ac7 100644 --- a/Sources/NBKCoreKit/Models/NBKPrimeSieve.swift +++ b/Sources/NBKCoreKit/Models/NBKPrimeSieve.swift @@ -717,7 +717,7 @@ extension NBKPrimeSieve { /// 5) [6A, 6B, 2A, 6D, 6E, 2B] // 6B, 6E /// 6) [6A, 6B, 6C, 6D, 6E, 6F] // 6C, 6F /// - /// The idea is to reuse words and subsequences whenever possible. + /// The idea is to reuse elements and subsequences whenever possible. /// /// - Important: The sieve culls even numbers by omission, so start with `[3,5]`. /// @@ -736,7 +736,7 @@ extension NBKPrimeSieve { patternIndex.remainder &+= current.prime }; chunk.formOnesComplement() //=--------------------------= - // pattern: reuse words + // pattern: reuse elements //=--------------------------= var ((destination)) = patternIndex.quotient while destination < current.product { diff --git a/Sources/NBKFlexibleWidthKit/IntXLOrUIntXL.swift b/Sources/NBKFlexibleWidthKit/IntXLOrUIntXL.swift new file mode 100644 index 00000000..ec467729 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/IntXLOrUIntXL.swift @@ -0,0 +1,250 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x IntXL or UIntXL +//*============================================================================* + +public protocol IntXLOrUIntXL: NBKBinaryInteger, ExpressibleByStringLiteral where Magnitude == UIntXL { + + //=------------------------------------------------------------------------= + // MARK: Details x Words + //=------------------------------------------------------------------------= + + /// Creates a new instance from the given collection of `words`. + /// + /// The `words` are interpreted as a binary integer with the same signedness. + /// + /// - Note: This method returns zero when the given collection of `words` is empty. + /// + @inlinable init(words: some RandomAccessCollection) + + //=------------------------------------------------------------------------= + // MARK: Details x Comparisons + //=------------------------------------------------------------------------= + + /// A three-way comparison between `self` and `other` at `index`. + /// + /// - Parameters: + /// - other: Another integer instance. + /// - index: The non-negative offset of `other` measured in `Digit` positions. + /// + @inlinable func compared(to other: Self, at index: Int) -> Int + + /// A three-way comparison between `self` and `other` at `index`. + /// + /// - Parameters: + /// - other: Another integer instance. + /// - index: The non-negative offset of `other` measured in `Digit` positions. + /// + @_disfavoredOverload @inlinable func compared(to other: Digit, at index: Int) -> Int + + //=------------------------------------------------------------------------= + // MARK: Details x Addition + //=------------------------------------------------------------------------= + + @inlinable mutating func add(_ other: Self, at index: Int) + + @_disfavoredOverload @inlinable mutating func add(_ other: Digit, at index: Int) + + @inlinable func adding(_ other: Self, at index: Int) -> Self + + @_disfavoredOverload @inlinable func adding(_ other: Digit, at index: Int) -> Self + + //=------------------------------------------------------------------------= + // MARK: Details x Subtraction + //=------------------------------------------------------------------------= + + @inlinable mutating func subtract(_ other: Self, at index: Int) + + @_disfavoredOverload @inlinable mutating func subtract(_ other: Digit, at index: Int) + + @inlinable func subtracting(_ other: Self, at index: Int) -> Self + + @_disfavoredOverload @inlinable func subtracting(_ other: Digit, at index: Int) -> Self + + //=------------------------------------------------------------------------= + // MARK: Details x Multiplication + //=------------------------------------------------------------------------= + + /// Forms the square product of this value. + @inlinable mutating func square() + + /// Returns the square product of this value. + @inlinable func squared() -> Self + + //=------------------------------------------------------------------------= + // MARK: Details x Exponentiation + //=------------------------------------------------------------------------= + + /// Returns the `power` of `self` raised to `exponent`. + /// + /// - Parameter exponent: A value greater than or equal to zero. + /// + @inlinable func power(_ exponent: Int) -> Self + + //=------------------------------------------------------------------------= + // MARK: Details x Shifts + //=------------------------------------------------------------------------= + + @inlinable mutating func bitShiftLeftSmart(by distance: Int) + + @inlinable func bitShiftedLeftSmart(by distance: Int) -> Self + + @inlinable mutating func bitShiftLeft(by distance: Int) + + @inlinable func bitShiftedLeft(by distance: Int) -> Self + + @inlinable mutating func bitShiftLeft(major: Int, minor: Int) + + @inlinable func bitShiftedLeft(major: Int, minor: Int) -> Self + + @inlinable mutating func bitShiftLeft(major: Int) + + @inlinable func bitShiftedLeft(major: Int) -> Self + + @inlinable mutating func bitShiftRightSmart(by distance: Int) + + @inlinable func bitShiftedRightSmart(by distance: Int) -> Self + + @inlinable mutating func bitShiftRight(by distance: Int) + + @inlinable func bitShiftedRight(by distance: Int) -> Self + + @inlinable mutating func bitShiftRight(major: Int, minor: Int) + + @inlinable func bitShiftedRight(major: Int, minor: Int) -> Self + + @inlinable mutating func bitShiftRight(major: Int) + + @inlinable func bitShiftedRight(major: Int) -> Self + + //=------------------------------------------------------------------------= + // MARK: Details x Update + //=------------------------------------------------------------------------= + + /// Updates this instance in-place so it equals `value`. + /// + /// - Note: This operation may be more efficient than allocating new storage. + /// + @inlinable mutating func update(_ value: Self) + + /// Updates this instance in-place so it equals `value`. + /// + /// - Note: This operation may be more efficient than allocating new storage. + /// + @inlinable mutating func update(_ value: Digit) + + //=------------------------------------------------------------------------= + // MARK: Details x Words + //=------------------------------------------------------------------------= + + /// Grants unsafe access to the words of this instance. + /// + /// ``` + /// ┌──────────────────────── = ───────────────────────────┐ + /// │ self │ words on a 64-bit machine │ + /// ├──────────────────────── = ───────────────────────────┤ + /// │ IntXL( ) │ [ 0 ] │ + /// │ IntXL( Int256.max) │ [~0, ~0, ~0, ~0/2 + 0 ] │ + /// │ IntXL( Int256.max) + 1 │ [ 0, 0, 0, ~0/2 + 1, 0] │ + /// │ IntXL( Int256.min) │ [ 0, 0, 0, ~0/2 + 1 ] │ + /// │ IntXL( Int256.min) + 1 │ [~0, ~0, ~0, ~0/2 + 0, ~0] │ + /// │ IntXL(UInt256.max) │ [~0, ~0, ~0, ~0/1 + 0, 0] │ + /// │ IntXL(UInt256.max) + 1 │ [ 0, 0, 0, 0/1 + 0, 1] │ + /// ├──────────────────────── = ───────────────────────────┤ + /// │ UIntXL( ) │ [ 0 ] │ + /// │ UIntXL( Int256.max) │ [~0, ~0, ~0, ~0/2 + 0 ] │ + /// │ UIntXL( Int256.max) + 1 │ [ 0, 0, 0, ~0/2 + 1 ] │ + /// │ UIntXL(UInt256.max) │ [~0, ~0, ~0, ~0/1 + 0 ] │ + /// │ UIntXL(UInt256.max) + 1 │ [ 0, 0, 0, 0/1 + 0, 1] │ + /// └──────────────────────── = ───────────────────────────┘ + /// ``` + /// + @inlinable func withUnsafeBufferPointer( + _ body: (UnsafeBufferPointer) throws -> T) rethrows -> T + + /// Grants unsafe access to the mutable words of this instance. + /// + /// ``` + /// ┌──────────────────────── = ───────────────────────────┐ + /// │ self │ words on a 64-bit machine │ + /// ├──────────────────────── = ───────────────────────────┤ + /// │ IntXL( ) │ [ 0 ] │ + /// │ IntXL( Int256.max) │ [~0, ~0, ~0, ~0/2 + 0 ] │ + /// │ IntXL( Int256.max) + 1 │ [ 0, 0, 0, ~0/2 + 1, 0] │ + /// │ IntXL( Int256.min) │ [ 0, 0, 0, ~0/2 + 1 ] │ + /// │ IntXL( Int256.min) + 1 │ [~0, ~0, ~0, ~0/2 + 0, ~0] │ + /// │ IntXL(UInt256.max) │ [~0, ~0, ~0, ~0/1 + 0, 0] │ + /// │ IntXL(UInt256.max) + 1 │ [ 0, 0, 0, 0/1 + 0, 1] │ + /// ├──────────────────────── = ───────────────────────────┤ + /// │ UIntXL( ) │ [ 0 ] │ + /// │ UIntXL( Int256.max) │ [~0, ~0, ~0, ~0/2 + 0 ] │ + /// │ UIntXL( Int256.max) + 1 │ [ 0, 0, 0, ~0/2 + 1 ] │ + /// │ UIntXL(UInt256.max) │ [~0, ~0, ~0, ~0/1 + 0 ] │ + /// │ UIntXL(UInt256.max) + 1 │ [ 0, 0, 0, 0/1 + 0, 1] │ + /// └──────────────────────── = ───────────────────────────┘ + /// ``` + /// + /// - Note: The words of this instance will be normalized after this operation. + /// + @inlinable mutating func withUnsafeMutableBufferPointer( + _ body: (inout UnsafeMutableBufferPointer) throws -> T) rethrows -> T + + /// Creates a new instance with unsafe access to its uninitialized words. + /// + /// The `init` is responsible for initializing all `count` words given to it. + /// + /// - Note: While the resulting instance may have a capacity larger than the + /// requested amount, the buffer passed to `init` will cover exactly the requested + /// number of words. + /// + /// - Note: This is a non-throwing convenience for `uninitialized(capacity:init:)`. + /// + /// ### Semantics when there is no initialized prefix + /// + /// It returns zero when there is no initialized prefix because the following + /// expressions must return the same values: + /// + /// ```swift + /// 1. Self.init(words: words) // this is zero when words == [] + /// 2. Self.uninitialized(count: words.count) { _ = $0.initialize(from: words).index } + /// 3. Self.uninitialized(capacity: words.count) { $1 = $0.initialize(from: words).index } + /// ``` + /// + @inlinable static func uninitialized( + count: Int, init: (inout UnsafeMutableBufferPointer) -> Void) -> Self + + /// Creates a new instance with unsafe access to its uninitialized words. + /// + /// The `init` is responsible for initializing up to `capacity` prefixing words. + /// The `init` is given a buffer and an initialized prefix count. All words in + /// the prefix must be initialized and all words after it must be uninitialized. + /// This postcondition must hold even when the `init` throws an error. + /// + /// - Note: While the resulting instance may have a capacity larger than the + /// requested amount, the buffer passed to `init` will cover exactly the requested + /// number of words. + /// + /// ### Semantics when there is no initialized prefix + /// + /// It returns zero when there is no initialized prefix because the following + /// expressions must return the same values: + /// + /// ```swift + /// 1. Self.init(words: words) // this is zero when words == [] + /// 2. Self.uninitialized(count: words.count) { _ = $0.initialize(from: words).index } + /// 3. Self.uninitialized(capacity: words.count) { $1 = $0.initialize(from: words).index } + /// ``` + /// + @inlinable static func uninitialized( + capacity: Int, init: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows -> Self +} diff --git a/Sources/NBKFlexibleWidthKit/Models/NBKFibonacciXL.swift b/Sources/NBKFlexibleWidthKit/Models/NBKFibonacciXL.swift new file mode 100644 index 00000000..09d31bd3 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/Models/NBKFibonacciXL.swift @@ -0,0 +1,125 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x FibonacciXL +//*============================================================================* + +/// The [Fibonacci sequence](https://en.wikipedia.org/wiki/fibonacci_sequence)\. +/// +/// It is represented by an index and two consecutive elements. +/// +/// ```swift +/// NBKFibonacciXL(0) // (index: 0, element: 0, next: 1) +/// NBKFibonacciXL(1) // (index: 1, element: 1, next: 1) +/// NBKFibonacciXL(2) // (index: 2, element: 1, next: 2) +/// NBKFibonacciXL(3) // (index: 3, element: 2, next: 3) +/// NBKFibonacciXL(4) // (index: 4, element: 3, next: 5) +/// NBKFibonacciXL(5) // (index: 5, element: 5, next: 8) +/// ``` +/// +/// ### Fast double-and-add algorithm +/// +/// The fast double-and-add algorithm is powered by this observation: +/// +/// ```swift +/// f(x + 0 + 1) == f(x) * 0000 + f(x + 1) * 00000001 +/// f(x + 1 + 1) == f(x) * 0001 + f(x + 1) * 00000001 +/// f(x + 2 + 1) == f(x) * 0001 + f(x + 1) * 00000002 +/// f(x + 3 + 1) == f(x) * 0002 + f(x + 1) * 00000003 +/// f(x + 4 + 1) == f(x) * 0003 + f(x + 1) * 00000005 +/// f(x + 5 + 1) == f(x) * 0005 + f(x + 1) * 00000008 +/// f(x + 6 + 1) == f(x) * 0008 + f(x + 1) * 00000013 +/// ───────────────────────────────────────────────── +/// f(x + y + 1) == f(x) * f(y) + f(x + 1) * f(y + 1) +/// f(x + x + 1) == f(x) ^ 0002 + f(x + 1) ^ 00000002 +/// ``` +/// +@frozen public struct NBKFibonacciXL: CustomStringConvertible { + + //=------------------------------------------------------------------------= + // MARK: State + //=------------------------------------------------------------------------= + + @usableFromInline var i = UInt() + @usableFromInline var a = UIntXL(digit: 0) + @usableFromInline var b = UIntXL(digit: 1) + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + /// Creates the first sequence pair. + @inlinable public init() { } + + /// Creates the sequence pair at the given `index`. + @inlinable public init(_ index: UInt) { + var mask = 1 as UInt &<< UInt(bitPattern: index.bitWidth &+ index.leadingZeroBitCount.onesComplement()) + while !mask.isZero { self.double(); if !(index & mask).isZero { self.increment() }; mask &>>= 1 as UInt } + } + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + /// The sequence `index`. + @inlinable public var index: UInt { + self.i + } + + /// The sequence `element` at `index`. + @inlinable public var element: UIntXL { + self.a + } + + /// The sequence `element` at `index + 1`. + @inlinable public var next: UIntXL { + self.b + } + + @inlinable public var description: String { + self.element.description + } + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + /// Forms the sequence pair at `index + 1`. + @inlinable public mutating func increment() { + i += 1 + a += b + Swift.swap(&a, &b) + } + + /// Forms the sequence pair at `index - 1`. + @inlinable public mutating func decrement() { + i -= 1 + b -= a + Swift.swap(&a, &b) + } + + /// Forms the sequence pair at `index * 2`. + @inlinable public mutating func double() { + var (x): UIntXL // f(2 * index + 0) + x = b.bitShiftedLeft(major: Int.zero, minor: Int.one) + x -= a + x *= a + + var (y): UIntXL // f(2 * index + 1) + y = b.squared() + y += a.squared() + + i *= 2 + a = x + b = y + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Addition+Digit.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Addition+Digit.swift new file mode 100644 index 00000000..e9f4ee16 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Addition+Digit.swift @@ -0,0 +1,56 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Addition x Digit x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public static func +=(lhs: inout Self, rhs: UInt) { + lhs.add(rhs, at: 0 as Int) + } + + @_disfavoredOverload @inlinable public static func +(lhs: Self, rhs: UInt) -> Self { + lhs.adding(rhs, at: 0 as Int) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Index + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func add(_ other: UInt, at index: Int) { + //=--------------------------------------= + if other.isZero { return } + //=--------------------------------------= + self.storage.resize(minCount: index + 1) + + let overflow = self.storage.withUnsafeMutableBufferPointer(in: index...) { + NBK.SUISS.increment(&$0, by: other).overflow + } + + if overflow { + self.storage.append(1 as UInt) + } + + Swift.assert(self.storage.isNormal) + } + + @_disfavoredOverload @inlinable public func adding(_ other: UInt, at index: Int) -> Self { + var result = self + result.add(other, at: index) + return result as Self + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Addition.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Addition.swift new file mode 100644 index 00000000..896f6620 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Addition.swift @@ -0,0 +1,58 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Addition x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable public static func +=(lhs: inout Self, rhs: Self) { + lhs.add(rhs, at: 0 as Int) + } + + @inlinable public static func +(lhs: Self, rhs: Self) -> Self { + lhs.adding(rhs, at: 0 as Int) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Index + //=------------------------------------------------------------------------= + + @inlinable public mutating func add(_ other: Self, at index: Int) { + //=--------------------------------------= + if other.isZero { return } + //=--------------------------------------= + self.storage.resize(minCount: index + other.storage.elements.count) + + let overflow = self.storage.withUnsafeMutableBufferPointer(in: index...) { slice in + other.storage.withUnsafeBufferPointer { other in + NBK.SUISS.increment(&slice, by: other).overflow + } + } + + if overflow { + self.storage.append(1 as UInt) + } + + Swift.assert(self.storage.isNormal) + } + + @inlinable public func adding(_ other: Self, at index: Int) -> Self { + var result = self + result.add(other, at: index) + return result as Self + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Bits.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Bits.swift new file mode 100644 index 00000000..3586afdc --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Bits.swift @@ -0,0 +1,53 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Bits x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable public init(bit: Bool) { + self.init(digit: Digit(bit: bit)) + } + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + @inlinable public var bitWidth: Int { + self.storage.elements.count * UInt.bitWidth + } + + @inlinable public var nonzeroBitCount: Int { + self.withUnsafeBufferPointer(NBK.SBISS.nonzeroBitCount(of:)) + } + + @inlinable public var leadingZeroBitCount: Int { + self.withUnsafeBufferPointer(NBK.SBISS.leadingZeroBitCount(of:)) + } + + @inlinable public var trailingZeroBitCount: Int { + self.withUnsafeBufferPointer(NBK.SBISS.trailingZeroBitCount(of:)) + } + + @inlinable public var mostSignificantBit: Bool { + self.last.mostSignificantBit + } + + @inlinable public var leastSignificantBit: Bool { + self.first.leastSignificantBit + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Comparisons.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Comparisons.swift new file mode 100644 index 00000000..e7192a0f --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Comparisons.swift @@ -0,0 +1,93 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Comparisons x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + @inlinable public var isZero: Bool { + self.withUnsafeBufferPointer({ $0.count == 1 && $0.first!.isZero }) + } + + @inlinable public var isLessThanZero: Bool { + false + } + + @inlinable public var isMoreThanZero: Bool { + !self.isZero + } + + @inlinable public var isPowerOf2: Bool { + self.withUnsafeBufferPointer({ NBK.SBISS.nonzeroBitCount(of: $0, equals: 1) }) + } + + @inlinable public func signum() -> Int { + Int(bit: !self.isZero) + } + + //=------------------------------------------------------------------------= + // MARK: Utilities + //=------------------------------------------------------------------------= + + @inlinable public func hash(into hasher: inout Hasher) { + hasher.combine(self.storage.elements) + } + + //=------------------------------------------------------------------------= + // MARK: Utilities + //=------------------------------------------------------------------------= + + @inlinable public static func ==(lhs: Self, rhs: Self) -> Bool { + lhs.compared(to: rhs).isZero + } + + @inlinable public static func <(lhs: Self, rhs: Self) -> Bool { + lhs.compared(to: rhs) == -1 + } + + @inlinable public func compared(to other: Self) -> Int { + self.storage.elements.withUnsafeBufferPointer { lhs in + other.storage.elements.withUnsafeBufferPointer { rhs in + NBK.SUISS.compare(lhs, to: rhs) + } + } + } + + @inlinable public func compared(to other: Self, at index: Int) -> Int { + self.storage.elements.withUnsafeBufferPointer { lhs in + other.storage.elements.withUnsafeBufferPointer { rhs in + NBK.SUISS.compare(lhs, to: rhs, at: index) + } + } + } + + @_disfavoredOverload @inlinable public func compared(to other: Digit) -> Int { + self.storage.elements.withUnsafeBufferPointer { lhs in + NBK.SBI.withUnsafeBufferPointer(to:other) { rhs in + NBK.SUISS.compare(lhs, to: rhs) + } + } + } + + @_disfavoredOverload @inlinable public func compared(to other: Digit, at index: Int) -> Int { + self.storage.elements.withUnsafeBufferPointer { lhs in + NBK.SBI.withUnsafeBufferPointer(to:other) { rhs in + NBK.SUISS.compare(lhs, to: rhs, at: index) + } + } + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Complements.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Complements.swift new file mode 100644 index 00000000..05e4cb78 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Complements.swift @@ -0,0 +1,59 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Complements x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Details x One's Complement + //=------------------------------------------------------------------------= + + @inlinable public mutating func formOnesComplement() { + self.withUnsafeMutableBufferPointer { + NBK.SBISS.formOnesComplement(&$0) + } + } + + @inlinable public func onesComplement() -> Self { + Self(normalizing: Storage(unchecked: Elements(self.storage.elements.lazy.map(~)))) + } + + //=------------------------------------------------------------------------= + // MARK: Details x Two's Complement + //=------------------------------------------------------------------------= + + @inlinable public mutating func formTwosComplementReportingOverflow() -> Bool { + self.withUnsafeMutableBufferPointer { + NBK.SUISS.formTwosComplementReportingOverflow(&$0) + } + } + + @inlinable public func twosComplementReportingOverflow() -> PVO { + var partialValue = self + let overflow = partialValue.formTwosComplementReportingOverflow() + return PVO(partialValue, overflow) + } + + @inlinable public mutating func formTwosComplementSubsequence(_ carry: Bool) -> Bool { + self.withUnsafeMutableBufferPointer { + NBK.SUISS.formTwosComplementSubsequence(&$0, carry: carry) + } + } + + @inlinable public func twosComplementSubsequence(_ carry: Bool) -> PVO { + var partialValue = self + let overflow = partialValue.formTwosComplementSubsequence(carry) + return PVO(partialValue, overflow) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Division+Digit.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Division+Digit.swift new file mode 100644 index 00000000..d418c52f --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Division+Digit.swift @@ -0,0 +1,66 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Division x Digit x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x Overflow + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func divideReportingOverflow(by other: Digit) -> Bool { + let pvo: PVO = self.dividedReportingOverflow(by: other) + self = pvo.partialValue + return pvo.overflow as Bool + } + + @_disfavoredOverload @inlinable public func dividedReportingOverflow(by other: Digit) -> PVO { + let qro: PVO> = self.quotientAndRemainderReportingOverflow(dividingBy: other) + return PVO(qro.partialValue.quotient, qro.overflow) + } + + @_disfavoredOverload @inlinable public mutating func formRemainderReportingOverflow(dividingBy other: Digit) -> Bool { + let pvo: PVO = self.remainderReportingOverflow(dividingBy: other) + self = Self(digit: pvo.partialValue) + return pvo.overflow as Bool + } + + @_disfavoredOverload @inlinable public func remainderReportingOverflow(dividingBy other: Digit) -> PVO { + let qro: PVO> = self.quotientAndRemainderReportingOverflow(dividingBy: other) + return PVO(qro.partialValue.remainder, qro.overflow) + } + + @_disfavoredOverload @inlinable public func quotientAndRemainderReportingOverflow(dividingBy other: Digit) -> PVO> { + var quotient = self + let remainder = quotient.formQuotientWithRemainderReportingOverflow(dividingBy: other) + return PVO(QR(quotient, remainder.partialValue), remainder.overflow) + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Algorithms +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x Overflow + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func formQuotientWithRemainderReportingOverflow(dividingBy other: Digit) -> PVO { + self.withUnsafeMutableBufferPointer { + NBK.SUISS.formQuotientWithRemainderReportingOverflow(dividing: &$0, by: other) + } + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Division.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Division.swift new file mode 100644 index 00000000..3fa300cc --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Division.swift @@ -0,0 +1,125 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Division x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x Overflow + //=------------------------------------------------------------------------= + + @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 func dividedReportingOverflow(by other: Self) -> PVO { + let qro: PVO> = self.quotientAndRemainderReportingOverflow(dividingBy: other) + return PVO(qro.partialValue.quotient, qro.overflow) + } + + @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 remainderReportingOverflow(dividingBy other: Self) -> PVO { + let qro: PVO> = self.quotientAndRemainderReportingOverflow(dividingBy: other) + return PVO(qro.partialValue.remainder, qro.overflow) + } + + @inlinable public func quotientAndRemainderReportingOverflow(dividingBy other: Self) -> PVO> { + self.quotientAndRemainderReportingOverflowUsingLongAlgorithm(dividingBy: other) + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Long Division Algorithms +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x Overflow x Private + //=------------------------------------------------------------------------= + + /// Performs long division after some fast-path checks. + @inlinable func quotientAndRemainderReportingOverflowUsingLongAlgorithm(dividingBy other: Self) -> PVO> { + var (remainder) = self + let (quotient, overflow) = remainder.formRemainderWithQuotientReportingOverflowUsingLongAlgorithm(dividingBy: other) + return PVO(QR(quotient, remainder), overflow) + } + + /// Performs long division after some fast-path checks. + @inlinable mutating func formRemainderWithQuotientReportingOverflowUsingLongAlgorithm(dividingBy other: Self) -> PVO { + //=--------------------------------------= + // divisor is zero + //=--------------------------------------= + if other.isZero { + return PVO(self, true) + } + //=--------------------------------------= + // divisor is one word + //=--------------------------------------= + if other.count == Int.one { + let (q, r) = self.quotientAndRemainder(dividingBy: other.first) + self.update(r) + return PVO((q), false) + } + //=--------------------------------------= + // divisor is greater than or equal + //=--------------------------------------= + let comparison = other.compared(to: self) + if comparison.isLessThanZero { + } else if comparison.isZero { + self.update(UInt.zero) + return PVO(Self.one, false) + } else { + return PVO(Self.zero, false) + } + //=--------------------------------------= + // normalization + //=--------------------------------------= + self.storage.append(UInt.zero) + + var other: Self = other + let shift: Int = other.last.leadingZeroBitCount + + if !shift.isZero { + self .storage.withUnsafeMutableBufferPointer({ NBK.SUI.bitShiftLeft(&$0, major: 0 as Int, minorAtLeastOne: shift) }) + other.storage.withUnsafeMutableBufferPointer({ NBK.SUI.bitShiftLeft(&$0, major: 0 as Int, minorAtLeastOne: shift) }) + } + //=--------------------------------------= + // division + //=--------------------------------------= + let quotient = Self.uninitialized(count: self.count - other.count) { quotient in + self .storage.withUnsafeMutableBufferPointer { dividend in + other.storage.withUnsafeBufferPointer/*---*/ { divisor in + NBK.SUI.initializeToQuotientFormRemainderByLongAlgorithm2111MSB("ient, dividing: ÷nd, by: divisor) + }}} + //=--------------------------------------= + // normalization + //=--------------------------------------= + if !shift.isZero { + self.storage.withUnsafeMutableBufferPointer({ NBK.SUI.bitShiftRight(&$0, major: 0 as Int, minorAtLeastOne: shift) }) + } + + self.storage.normalize() + Swift.assert(quotient.storage.isNormal) + //=--------------------------------------= + return PVO(partialValue: quotient, overflow: false) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Exponentiation.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Exponentiation.swift new file mode 100644 index 00000000..8646e5e2 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Exponentiation.swift @@ -0,0 +1,49 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Exponentiation x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + /// Returns the `power` of `self` raised to `exponent`. + /// + /// - Parameter exponent: A value greater than or equal to zero. + /// + @inlinable public func power(_ exponent: Int) -> Self { + //=--------------------------------------= + if exponent == 0 { return Self.one } + else if exponent == 1 { return self } + //=--------------------------------------= + Swift.assert(exponent > 001) + var power = Self(digit: 001) + var multiplier: Self = self + var pattern = UInt(exponent) + //=--------------------------------------= + repeat { + + if pattern.isOdd { + power *= multiplier + } + + pattern &>>= 000001 + multiplier.square() + + } while !pattern.isZero + //=--------------------------------------= + return power as Self as Self as Self as Self + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Literals.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Literals.swift new file mode 100644 index 00000000..361a9d72 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Literals.swift @@ -0,0 +1,88 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Literals x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=-------------------------------------------------------------------------= + // MARK: Details x Integer Literal Type + //=-------------------------------------------------------------------------= + #if SBI && swift(>=5.8) + + @inlinable public init(integerLiteral source: StaticBigInt) { + if let value = Self(exactlyIntegerLiteral: source) { self = value } else { + preconditionFailure("\(Self.description) cannot represent \(source)") + } + } + + /// - Warning: This method is only public for RELEASE mode testing. + @inlinable public init?(exactlyIntegerLiteral source: StaticBigInt) { + guard Self.isSigned || source.signum() >= 0 as Int else { return nil } + //=--------------------------------------= + let width = Swift.max(1, source.bitWidth - Int(bit: !Self.isSigned)) + let major = NBK.PBI .quotient(dividing: NBK.ZeroOrMore(unchecked: width), by: NBK.PowerOf2(bitWidth: UInt.self)) + let minor = NBK.PBI.remainder(dividing: NBK.ZeroOrMore(unchecked: width), by: NBK.PowerOf2(bitWidth: UInt.self)) + let count = major &+ Int(bit: minor.isMoreThanZero) + //=--------------------------------------= + self = Self.uninitialized(count: count) { words in + for index in words.indices { + words.baseAddress!.advanced(by: index).initialize(to: source[index]) + } + } + } + + #else + + @inlinable public init(integerLiteral source: Digit.IntegerLiteralType) { + self.init(digit: Digit(integerLiteral: source)) + } + + #endif + //=------------------------------------------------------------------------= + // MARK: Details x String Literal Type + //=------------------------------------------------------------------------= + + /// Creates a new instance from the given string literal. + /// + /// The string literal may contain a plus or minus sign (+ or -), followed by + /// an optional radix indicator (0b, 0o or 0x), then one or more numeric digits + /// (0-9) or letters (a-z or A-Z). If the string literal uses an invalid format, + /// or its value cannot be represented, a runtime error may occur. + /// + /// ``` + /// ┌───────── → ─────────────┐ + /// │ literal │ self │ + /// ├───────── → ─────────────┤ + /// │ "123" │ Int256( 123) │ + /// │ "+0x123" │ Int256( 291) │ + /// │ "-0x123" │ Int256(-291) │ + /// │ "~OX123" │ error │ + /// └───────── → ─────────────┘ + /// ``` + /// + /// - Note: The decoding strategy is case insensitive. + /// + @inlinable public init(stringLiteral description: StaticString) { + if let value = Self(exactlyStringLiteral: description) { self = value } else { + preconditionFailure("\(Self.description) cannot represent \(description)") + } + } + + /// - Warning: This method is only public for RELEASE mode testing. + @inlinable public init?(exactlyStringLiteral description: StaticString) { + let decoder = NBK.IntegerDescription.DecoderDecodingRadix() + guard let components: SM = decoder.decode(description) else { return nil } + self.init(sign: components.sign, magnitude: components.magnitude) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Logic.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Logic.swift new file mode 100644 index 00000000..c32ef9eb --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Logic.swift @@ -0,0 +1,100 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Logic x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x NOT + //=------------------------------------------------------------------------= + + @inlinable public static prefix func ~(x: Self) -> Self { + x.onesComplement() + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x AND + //=------------------------------------------------------------------------= + + @inlinable public static func &=(lhs: inout Self, rhs: Self) { + lhs.storage.downsizeThenFormInIntersection(with: rhs.storage, each: &) + lhs.storage.normalize() + } + + @inlinable public static func &(lhs: Self, rhs: Self) -> Self { + var lhs = lhs; lhs &= rhs; return lhs + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x OR + //=------------------------------------------------------------------------= + + @inlinable public static func |=(lhs: inout Self, rhs: Self) { + lhs.storage.upsizeThenFormInIntersection(with: rhs.storage, each: |) + Swift.assert(lhs.storage.isNormal) + } + + @inlinable public static func |(lhs: Self, rhs: Self) -> Self { + var lhs = lhs; lhs |= rhs; return lhs + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x XOR + //=------------------------------------------------------------------------= + + @inlinable public static func ^=(lhs: inout Self, rhs: Self) { + lhs.storage.upsizeThenFormInIntersection(with: rhs.storage, each: ^) + lhs.storage.normalize() + } + + @inlinable public static func ^(lhs: Self, rhs: Self) -> Self { + var lhs = lhs; lhs ^= rhs; return lhs + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Logic x Unsigned x Storage +//*============================================================================* +//=----------------------------------------------------------------------------= +// MARK: + Algorithms +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude.Storage { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable mutating func upsizeThenFormInIntersection(with other: Self, each element: (UInt, UInt) -> UInt) { + self.resize(minCount: other.elements.count) + self.withUnsafeMutableBufferPointer { lhs in + other.withUnsafeBufferPointer { rhs in + for index in rhs.indices { + lhs[index] = element(lhs[index], rhs[index]) + } + } + } + } + + @inlinable mutating func downsizeThenFormInIntersection(with other: Self, each element: (UInt, UInt) -> UInt) { + self.resize(maxCount: other.elements.count) + self.withUnsafeMutableBufferPointer { lhs in + other.withUnsafeBufferPointer { rhs in + for index in lhs.indices { + lhs[index] = element(lhs[index], rhs[index]) + } + } + } + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Multiplication+Digit.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Multiplication+Digit.swift new file mode 100644 index 00000000..8c937f0d --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Multiplication+Digit.swift @@ -0,0 +1,58 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Multiplication x Digit x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public static func *=(lhs: inout Self, rhs: UInt) { + lhs.multiply(by: rhs, add: 0 as UInt) + } + + @_disfavoredOverload @inlinable public static func *(lhs: Self, rhs: UInt) -> Self { + lhs.multiplied(by: rhs, adding: 0 as UInt) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Addition + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func multiply(by multiplier: UInt, add addend: UInt) { + //=--------------------------------------= + if multiplier.isZero { + return self.update(addend) + } + //=--------------------------------------= + self.storage.reserveCapacity(self.storage.elements.count + 1) + + let carry = self.storage.withUnsafeMutableBufferPointer { + NBK.SUISS.multiply(&$0, by: multiplier, add: addend) + } + + if !carry.isZero { + self.storage.append(carry) + } + + Swift.assert(self.storage.isNormal) + } + + @_disfavoredOverload @inlinable public func multiplied(by multiplier: UInt, adding addend: UInt) -> Self { + var result = self + result.multiply(by: multiplier, add: addend) + return result as Self + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Multiplication.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Multiplication.swift new file mode 100644 index 00000000..a93daac2 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Multiplication.swift @@ -0,0 +1,52 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Multiplication x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable public static func *=(lhs: inout Self, rhs: Self) { + lhs = lhs * rhs + } + + @inlinable public static func *(lhs: Self, rhs: Self) -> Self { + lhs.withUnsafeBufferPointer { lhs in + rhs.withUnsafeBufferPointer { rhs in + Self.uninitialized(count: lhs.count + rhs.count) { + NBK.SUISS.initialize(&$0, to: lhs, times: rhs) + } + } + } + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Square + //=------------------------------------------------------------------------= + + @inlinable public mutating func square() { + self = self.squared() + } + + @inlinable public func squared() -> Self { + self.withUnsafeBufferPointer{ words in + Self.uninitialized(count: words.count * 2) { + NBK.SUISS.initialize(&$0, toSquareProductOf: words) + } + } + } +} + diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Numbers.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Numbers.swift new file mode 100644 index 00000000..bb703551 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Numbers.swift @@ -0,0 +1,94 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Numbers x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Constants + //=------------------------------------------------------------------------= + + public static let zero = Self(digit: 0) + + public static let one = Self(digit: 1) + + //=------------------------------------------------------------------------= + // MARK: Initializers x Digit + //=------------------------------------------------------------------------= + + @inlinable public init(digit: UInt) { + self.init(unchecked: Storage(unchecked: [digit])) + } + + //=------------------------------------------------------------------------= + // MARK: Initializers x Binary Integer + //=------------------------------------------------------------------------= + + @inlinable public init(_ source: some BinaryInteger) { + if let value = Self(exactly: source) { self = value } else { + preconditionFailure("\(Self.description) cannot represent \(source)") + } + } + + @inlinable public init?(exactly source: some BinaryInteger) { + guard source.signum() >= 0 else { return nil } + self.init(words: source.words) + } + + @inlinable public init(clamping source: some BinaryInteger) { + self = Self(exactly: source) ?? (0 as Self) + } + + @inlinable public init(truncatingIfNeeded source: some BinaryInteger) { + self.init(words: source.words) + } + + //=------------------------------------------------------------------------= + // MARK: Initializers x Binary Floating Point + //=------------------------------------------------------------------------= + + @inlinable public init(_ source: some BinaryFloatingPoint) { + if let value = Self(exactly: source.rounded(.towardZero)) { self = value } else { + preconditionFailure("\(Self.description) cannot represent \(source)") + } + } + + @inlinable public init?(exactly source: some BinaryFloatingPoint) { + guard source.sign == FloatingPointSign.plus else { return nil } + //=--------------------------------------= + if source.isZero { self.init(); return } + guard source.isFinite else { return nil } + let value = source.rounded(.towardZero) + guard value == source else { return nil } + //=--------------------------------------= + let exponent = Int(source.exponent) + let ratio = exponent.quotientAndRemainder(dividingBy: UInt.bitWidth) + //=--------------------------------------= + self.init(exactly: source.significandBitPattern) + self >>= type(of: source).significandBitCount - exponent + self.add(UInt(1) << ratio.remainder, at: ratio.quotient) + } + + //=------------------------------------------------------------------------= + // MARK: Initializers x Sign & Magnitude + //=------------------------------------------------------------------------= + + @inlinable public init?(magnitude: Magnitude) { + self = magnitude + } + + @inlinable public init?(sign: FloatingPointSign, magnitude: Magnitude) { + if sign == FloatingPointSign.plus || magnitude.isZero { self = magnitude } else { return nil } + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Shifts.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Shifts.swift new file mode 100644 index 00000000..eb32772d --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Shifts.swift @@ -0,0 +1,253 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Shifts x Unsigned +//*============================================================================* +//=----------------------------------------------------------------------------= +// MARK: + Left +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable public static func <<=(lhs: inout Self, rhs: some BinaryInteger) { + lhs.bitShiftLeftSmart(by: NBK.initOrBitCast(clamping: rhs, as: Int.self)) + } + + @inlinable public static func <<(lhs: Self, rhs: some BinaryInteger) -> Self { + var lhs = lhs; lhs <<= rhs; return lhs + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Int + //=------------------------------------------------------------------------= + + @inlinable public mutating func bitShiftLeftSmart(by distance: Int) { + if distance >= 0 { + self.bitShiftLeft (by: distance) + } else { + self.bitShiftRight(by: NBK.initOrBitCast(clamping: distance.magnitude, as: Int.self)) + } + } + + @inlinable public func bitShiftedLeftSmart(by distance: Int) -> Self { + var result = self; result.bitShiftLeftSmart(by: distance); return result + } + + @inlinable public mutating func bitShiftLeft(@NBK.ZeroOrMore by distance: Int) { + let major = NBK.PBI .quotient(dividing: $distance, by: NBK.PowerOf2(bitWidth: UInt.self)) + let minor = NBK.PBI.remainder(dividing: $distance, by: NBK.PowerOf2(bitWidth: UInt.self)) + return self.bitShiftLeft(major: major, minor: minor) + } + + @inlinable public func bitShiftedLeft(by distance: Int) -> Self { + var result = self; result.bitShiftLeft(by: distance); return result + } + + @inlinable public mutating func bitShiftLeft(major: Int, minor: Int) { + //=--------------------------------------= + if minor.isZero { + return self.bitShiftLeft(major: major) + } + //=--------------------------------------= + self.bitShiftLeft(major: major, minorAtLeastOne: minor) + } + + @inlinable public func bitShiftedLeft(major: Int, minor: Int) -> Self { + var result = self; result.bitShiftLeft(major: major, minor: minor); return result + } + + @inlinable public mutating func bitShiftLeft(major: Int) { + //=--------------------------------------= + if major.isZero { return } + //=--------------------------------------= + self.bitShiftLeft(majorAtLeastOne: major) + } + + @inlinable public func bitShiftedLeft(major: Int) -> Self { + var result = self; result.bitShiftLeft(major: major); return result + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Left x Algorithms +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x Int x Private + //=------------------------------------------------------------------------= + + /// Performs a left shift. + /// + /// - Parameters: + /// - major: `0 <= major` + /// - minor: `1 <= minor < UInt.bitWidth` + /// + @inlinable mutating func bitShiftLeft(major: Int, minorAtLeastOne minor: Int) { + //=--------------------------------------= + if self.isZero { return } + //=--------------------------------------= + let rollover = Int(bit: self.leadingZeroBitCount < minor) + self.storage.resize(minCount: self.storage.elements.count + major + rollover) + + self.storage.withUnsafeMutableBufferPointer { + NBK.SUI.bitShiftLeft(&$0, major: major, minorAtLeastOne: minor) + } + + Swift.assert(self.storage.isNormal) + } + + /// Performs a left shift. + /// + /// - Parameters: + /// - major: `1 <= major` + /// + @inlinable mutating func bitShiftLeft(majorAtLeastOne major: Int) { + //=--------------------------------------= + if self.isZero { return } + //=--------------------------------------= + self.storage.resize(minCount: self.storage.elements.count + major) + + self.storage.withUnsafeMutableBufferPointer { + NBK.SUI.bitShiftLeft(&$0, majorAtLeastOne: major) + } + + Swift.assert(self.storage.isNormal) + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Right +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable public static func >>=(lhs: inout Self, rhs: some BinaryInteger) { + lhs.bitShiftRightSmart(by: NBK.initOrBitCast(clamping: rhs, as: Int.self)) + } + + @inlinable public static func >>(lhs: Self, rhs: some BinaryInteger) -> Self { + var lhs = lhs; lhs >>= rhs; return lhs + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Int + //=------------------------------------------------------------------------= + + @inlinable public mutating func bitShiftRightSmart(by distance: Int) { + if distance >= 0 { + self.bitShiftRight(by: distance) + } else { + self.bitShiftLeft (by: NBK.initOrBitCast(clamping: distance.magnitude, as: Int.self)) + } + } + + @inlinable public func bitShiftedRightSmart(by distance: Int) -> Self { + var result = self; result.bitShiftRightSmart(by: distance); return result + } + + @inlinable public mutating func bitShiftRight(@NBK.ZeroOrMore by distance: Int) { + let major = NBK.PBI .quotient(dividing: $distance, by: NBK.PowerOf2(bitWidth: UInt.self)) + let minor = NBK.PBI.remainder(dividing: $distance, by: NBK.PowerOf2(bitWidth: UInt.self)) + return self.bitShiftRight(major: major, minor: minor) + } + + @inlinable public func bitShiftedRight(by distance: Int) -> Self { + var result = self; result.bitShiftRight(by: distance); return result + } + + @inlinable public mutating func bitShiftRight(major: Int, minor: Int) { + //=--------------------------------------= + if minor.isZero { + return self.bitShiftRight(major: major) + } + //=--------------------------------------= + self.bitShiftRight(major: major, minorAtLeastOne: minor) + } + + @inlinable public func bitShiftedRight(major: Int, minor: Int) -> Self { + var result = self; result.bitShiftRight(major: major, minor: minor); return result + } + + @inlinable public mutating func bitShiftRight(major: Int) { + //=--------------------------------------= + if major.isZero { return } + //=--------------------------------------= + self.bitShiftRight(majorAtLeastOne: major) + } + + @inlinable public func bitShiftedRight(major: Int) -> Self { + var result = self; result.bitShiftRight(major: major); return result + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Right x Algorithms +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations x Int x Private + //=------------------------------------------------------------------------= + + /// Performs an unsigned right shift. + /// + /// - Parameters: + /// - major: `1 <= major` + /// - minor: `0 <= minor < UInt.bitWidth` + /// + @inlinable mutating func bitShiftRight(major: Int, minorAtLeastOne minor: Int) { + //=--------------------------------------= + let rollover = Int(bit: 0 <= minor + self.leadingZeroBitCount - UInt.bitWidth) + let maxCount = self.storage.elements.count - major - rollover + //=--------------------------------------= + if maxCount <= 0 { + return self.update(0 as UInt) + } + //=--------------------------------------= + self.storage.withUnsafeMutableBufferPointer { + NBK.SUI.bitShiftRight(&$0, major: major, minorAtLeastOne: minor) + } + + self.storage.resize(maxCount: maxCount) + Swift.assert(self.storage.isNormal) + } + + /// Performs an unsigned right shift. + /// + /// - Parameters: + /// - major: `1 <= major` + /// + @inlinable mutating func bitShiftRight(majorAtLeastOne major: Int) { + //=--------------------------------------= + if self.storage.elements.count <= major { + return self.update(0 as UInt) + } + //=--------------------------------------= + self.storage.withUnsafeMutableBufferPointer { + NBK.SUI.bitShiftRight(&$0, majorAtLeastOne: major) + } + + self.storage.resize(maxCount: self.storage.elements.count - major) + Swift.assert(self.storage.isNormal) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Storage.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Storage.swift new file mode 100644 index 00000000..98b435f6 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Storage.swift @@ -0,0 +1,68 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Size x Unsigned x Storage +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude.Storage { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable mutating func append(_ word: UInt) { + self.elements.append(word) + } + + @inlinable mutating func resize(minCount: Int) { + self.reserveCapacity(minCount) + appending: while self.elements.count < minCount { + self.elements.append(0 as UInt) + } + } + + @inlinable mutating func resize(maxCount: Int) { + precondition(maxCount.isMoreThanZero) + if self.elements.count > maxCount { + self.elements.removeSubrange(maxCount...) + } + } + + @inlinable mutating func reserveCapacity(_ minCapacity: Int) { + self.elements.reserveCapacity(minCapacity) + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Normalization +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude.Storage { + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + @inlinable var isNormal: Bool { + self.elements.count == 1 || !self.elements.last!.isZero + } + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable mutating func normalize() { + trimming: while self.elements.count > 1, self.elements.last!.isZero { + self.elements.removeLast() + } + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Subtraction+Digit.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Subtraction+Digit.swift new file mode 100644 index 00000000..6fbdef92 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Subtraction+Digit.swift @@ -0,0 +1,80 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Subtraction x Digit x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public static func -=(lhs: inout Self, rhs: UInt) { + lhs.subtract(rhs, at: 0 as Int) + } + + @_disfavoredOverload @inlinable public static func -(lhs: Self, rhs: UInt) -> Self { + lhs.subtracting(rhs, at: 0 as Int) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Overflow + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func subtractReportingOverflow(_ other: UInt) -> Bool { + self.subtractReportingOverflow(other, at: 0 as Int) + } + + @_disfavoredOverload @inlinable public func subtractingReportingOverflow(_ other: UInt) -> PVO { + self.subtractingReportingOverflow(other, at: 0 as Int) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Index + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func subtract(_ other: UInt, at index: Int) { + let overflow: Bool = self.subtractReportingOverflow(other, at: index) + precondition(!overflow, NBK.callsiteOverflowInfo()) + } + + @_disfavoredOverload @inlinable public func subtracting(_ other: UInt, at index: Int) -> Self { + let pvo: PVO = self.subtractingReportingOverflow(other, at: index) + precondition(!pvo.overflow, NBK.callsiteOverflowInfo()) + return pvo.partialValue as Self + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Index x Overflow + //=------------------------------------------------------------------------= + + @_disfavoredOverload @inlinable public mutating func subtractReportingOverflow(_ other: UInt, at index: Int) -> Bool { + //=--------------------------------------= + if other.isZero { return false } + //=--------------------------------------= + self.storage.resize(minCount: index + 1) + + let overflow = self.storage.withUnsafeMutableBufferPointer(in: index...) { + NBK.SUISS.decrement(&$0, by: other).overflow + } + + self.storage.normalize() + return overflow as Bool + } + + @_disfavoredOverload @inlinable public func subtractingReportingOverflow(_ other: UInt, at index: Int) -> PVO { + var partialValue = self + let overflow: Bool = partialValue.subtractReportingOverflow(other, at: index) + return PVO(partialValue, overflow) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Subtraction.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Subtraction.swift new file mode 100644 index 00000000..88635b13 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Subtraction.swift @@ -0,0 +1,82 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Subtraction x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable public static func -=(lhs: inout Self, rhs: Self) { + lhs.subtract(rhs, at: 0 as Int) + } + + @inlinable public static func -(lhs: Self, rhs: Self) -> Self { + lhs.subtracting(rhs, at: 0 as Int) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Overflow + //=------------------------------------------------------------------------= + + @inlinable public mutating func subtractReportingOverflow(_ other: Self) -> Bool { + self.subtractReportingOverflow(other, at: 0 as Int) + } + + @inlinable public func subtractingReportingOverflow(_ other: Self) -> PVO { + self.subtractingReportingOverflow(other, at: 0 as Int) + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Index + //=------------------------------------------------------------------------= + + @inlinable public mutating func subtract(_ other: Self, at index: Int) { + let overflow: Bool = self.subtractReportingOverflow(other, at: index) + precondition(!overflow, NBK.callsiteOverflowInfo()) + } + + @inlinable public func subtracting(_ other: Self, at index: Int) -> Self { + let pvo: PVO = self.subtractingReportingOverflow(other, at: index) + precondition(!pvo.overflow, NBK.callsiteOverflowInfo()) + return pvo.partialValue as Self + } + + //=------------------------------------------------------------------------= + // MARK: Transformations x Index x Overflow + //=------------------------------------------------------------------------= + + @inlinable public mutating func subtractReportingOverflow(_ other: Self, at index: Int) -> Bool { + //=--------------------------------------= + if other.isZero { return false } + //=--------------------------------------= + self.storage.resize(minCount: index + other.storage.elements.count) + + let overflow = self.storage.withUnsafeMutableBufferPointer(in: index...) { slice in + other.storage.withUnsafeBufferPointer { other in + NBK.SUISS.decrement(&slice, by: other).overflow + } + } + + self.storage.normalize() + return overflow as Bool + } + + @inlinable public func subtractingReportingOverflow(_ other: Self, at index: Int) -> PVO { + var partialValue = self + let overflow: Bool = partialValue.subtractReportingOverflow(other, at: index) + return PVO(partialValue, overflow) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Text.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Text.swift new file mode 100644 index 00000000..538b376a --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Text.swift @@ -0,0 +1,35 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Text x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Details x Decoding + //=------------------------------------------------------------------------= + + @inlinable public init?(_ description: some StringProtocol, radix: Int) { + let decoder = NBK.IntegerDescription.Decoder(radix: radix) + guard let components: SM = decoder.decode(description) else { return nil } + self.init(sign: components.sign, magnitude: components.magnitude) + } + + //=------------------------------------------------------------------------= + // MARK: Details x Encoding + //=------------------------------------------------------------------------= + + @inlinable public func description(radix: Int, uppercase: Bool) -> String { + NBK.IntegerDescription.Encoder(radix: radix, uppercase: uppercase).encode(self) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Update.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Update.swift new file mode 100644 index 00000000..a08baded --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Update.swift @@ -0,0 +1,29 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Update x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Transformations + //=------------------------------------------------------------------------= + + @inlinable public mutating func update(_ value: Self) { + self.storage.elements.replaceSubrange(self.storage.elements.indices, with: value.storage.elements) + } + + @inlinable public mutating func update(_ value: Digit) { + self.storage.elements.replaceSubrange(self.storage.elements.indices, with: CollectionOfOne(value)) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Collection.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Collection.swift new file mode 100644 index 00000000..1e0959d1 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Collection.swift @@ -0,0 +1,57 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Double Width x Words x Collection +//*============================================================================* +//=----------------------------------------------------------------------------= +// MARK: + Elements +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + /// The least significant word. + /// + /// - Note: This member is required by `Swift.BinaryInteger`. + /// + @inlinable public var _lowWord: UInt { + self.first as UInt + } + + /// The least significant word. + @inlinable public var first: UInt { + self.withUnsafeBufferPointer({ $0[0] }) + } + + /// The most significant word. + @inlinable public var last: UInt { + self.withUnsafeBufferPointer({ $0[$0.count - 1] }) + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Elements x Subscripts +//=----------------------------------------------------------------------------= + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + @inlinable public subscript(index: Int) -> UInt { + index < self.storage.elements.endIndex ? self.storage.elements[index] : 0 as UInt + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Pointers.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Pointers.swift new file mode 100644 index 00000000..b0d5833d --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Pointers.swift @@ -0,0 +1,91 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Words x Pointers x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Details x Contiguous UInt Collection + //=------------------------------------------------------------------------= + + /// Grants unsafe access to the words of this instance. + @inlinable public func withUnsafeBufferPointer( + _ body: (UnsafeBufferPointer) throws -> T) rethrows -> T { + try self.storage.withUnsafeBufferPointer(body) + } + + /// Grants unsafe access to the mutable words of this instance. + @inlinable public mutating func withUnsafeMutableBufferPointer( + _ body: (inout UnsafeMutableBufferPointer) throws -> T) rethrows -> T { + defer{ self.storage.normalize() } + return try self.storage.withUnsafeMutableBufferPointer(body) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Words x Pointers x Unsigned x Storage +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude.Storage { + + //=------------------------------------------------------------------------= + // MARK: Details x Contiguous UInt Collection + //=------------------------------------------------------------------------= + + /// Grants unsafe access to the words of this instance. + @inlinable public func withUnsafeBufferPointer( + _ body: (UnsafeBufferPointer) throws -> T) rethrows -> T { + try self.elements.withUnsafeBufferPointer(body) + } + + /// Grants unsafe access to the mutable words of this instance. + @inlinable public mutating func withUnsafeMutableBufferPointer( + _ body: (inout UnsafeMutableBufferPointer) throws -> T) rethrows -> T { + try self.elements.withUnsafeMutableBufferPointer(body) + } + + //=------------------------------------------------------------------------= + // MARK: Details x Contiguous UInt Collection x Sub Sequence + //=------------------------------------------------------------------------= + + /// Grants unsafe access to the words of this instance in the given `range`. + /// + /// ### Development + /// + /// This method is required for performance reasons (see slice arithmetic). + /// + @inlinable public func withUnsafeBufferPointer( + in range: some RangeExpression, perform body: (inout UnsafeBufferPointer) throws -> T) rethrows -> T { + try self.withUnsafeBufferPointer { + let range = range.relative(to: $0) + var slice = UnsafeBufferPointer(start: $0.baseAddress! + range.lowerBound, count: range.count) + return try body(&slice) as T + } + } + + /// Grants unsafe access to the mutable words of this instance in the given `range`. + /// + /// ### Development + /// + /// This method is required for performance reasons (see slice arithmetic). + /// + @inlinable public mutating func withUnsafeMutableBufferPointer( + in range: some RangeExpression, perform body: (inout UnsafeMutableBufferPointer) throws -> T) rethrows -> T { + try self.withUnsafeMutableBufferPointer { + let range = range.relative(to: $0) + var slice = UnsafeMutableBufferPointer(start: $0.baseAddress! + range.lowerBound, count: range.count) + return try body(&slice) as T + } + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Uninitialized.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Uninitialized.swift new file mode 100644 index 00000000..75af6ca6 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words+Uninitialized.swift @@ -0,0 +1,80 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Double Width x Words x Uninitialized +//*============================================================================* + +extension IntXLOrUIntXL { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable public static func uninitialized( + count: Int, init: (inout UnsafeMutableBufferPointer) -> Void) -> Self { + Self.uninitialized(capacity: count, init:{ $1 = $0.count; `init`(&$0) }) + } +} + +//*============================================================================* +// MARK: * NBK x Double Width x Words x Uninitialized x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable public static func uninitialized( + capacity: Int, init: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows -> Self { + Self(normalizing: try Storage.uninitialized(capacity: capacity, init: `init`)) + } +} + +//*============================================================================* +// MARK: * NBK x Double Width x Words x Uninitialized x Unsigned x Storage +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude.Storage { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + /// Creates a new instance with unsafe access to its uninitialized words. + /// + /// The `init` is responsible for initializing up to `capacity` prefixing words. + /// The `init` is given a buffer and an initialized prefix count. All words in + /// the prefix must be initialized and all words after it must be uninitialized. + /// This postcondition must hold even when the `init` throws an error. + /// + /// - Note: While the resulting instance may have a capacity larger than the + /// requested amount, the buffer passed to `init` will cover exactly the requested + /// number of words. + /// + /// ### Semantics when there is no initialized prefix + /// + /// It returns zero when there is no initialized prefix because the following + /// expressions must return the same values: + /// + /// ```swift + /// 1. Self.init(words: words) // this is zero when words == [] + /// 2. Self.uninitialized(count: words.count) { _ = $0.initialize(from: words).index } + /// 3. Self.uninitialized(capacity: words.count) { $1 = $0.initialize(from: words).index } + /// ``` + /// + @inlinable public static func uninitialized( + capacity: Int, init: (inout UnsafeMutableBufferPointer, inout Int) throws -> Void) rethrows -> Self { + Self(nonemptying: try Elements(unsafeUninitializedCapacity: capacity, initializingWith: `init`)) + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words.swift new file mode 100644 index 00000000..e894012b --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth+Words.swift @@ -0,0 +1,45 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width x Words x Unsigned +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + @inlinable public init(words: some Sequence) { + self.init(words: words, isSigned: Self.isSigned)! + } + + @inlinable public init?(words: some Sequence, isSigned: Bool) { + var storage = Storage(nonemptying: Elements(words)) + if isSigned && storage.elements.last!.mostSignificantBit { return nil } + + storage.normalize() + self.init(unchecked: storage) + } + + //=------------------------------------------------------------------------= + // MARK: Accessors + //=------------------------------------------------------------------------= + + @inlinable public var count: Int { + self.storage.elements.count + } + + @inlinable public var words: ContiguousArray { + self.storage.elements + } +} diff --git a/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth.swift b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth.swift new file mode 100644 index 00000000..7712b970 --- /dev/null +++ b/Sources/NBKFlexibleWidthKit/NBKFlexibleWidth.swift @@ -0,0 +1,153 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit + +//*============================================================================* +// MARK: * NBK x Flexible Width +//*============================================================================* + +/// A signed, flexible-width, binary integer. +/// +/// This name reserves a spot for a signed 2's-complement-in-memory integer. +/// +/// - Note: You can use `NBKSigned` until `IntXL` becomes available. +/// +@frozen public struct NBKFlexibleWidth { + + @usableFromInline typealias Elements = ContiguousArray + + //*========================================================================* + // MARK: * Magnitude + //*========================================================================* + + /// An unsigned, flexible-width, binary integer. + @frozen public struct Magnitude: NBKUnsignedInteger, IntXLOrUIntXL { + + public typealias Digit = UInt + + public typealias Words = ContiguousArray // TODO: make opaque + + @usableFromInline typealias Elements = NBKFlexibleWidth.Elements + + //=--------------------------------------------------------------------= + // MARK: State + //=--------------------------------------------------------------------= + + /// The integer's underlying storage. + /// + /// It must be `normal` and `nonempty` at the start and end of each access. + /// + @usableFromInline var storage: Storage + + //=--------------------------------------------------------------------= + // MARK: Initializers + //=--------------------------------------------------------------------= + + @inlinable init(_ storage: Storage) { + self.storage = storage + precondition(self.storage.isNormal) + } + + @inlinable init(normalizing storage: Storage) { + self.storage = storage + self.storage.normalize() + } + + @inlinable init(unchecked storage: Storage) { + self.storage = storage + Swift.assert(self.storage.isNormal) + } + + //*====================================================================* + // MARK: * Storage + //*====================================================================* + + /// An unsigned, resizable, collection of at least one word. + /// + /// Its operations have fixed-width semantics unless stated otherwise. + /// + @frozen @usableFromInline struct Storage { + + @usableFromInline typealias Elements = NBKFlexibleWidth.Elements + + //=----------------------------------------------------------------= + // MARK: State + //=----------------------------------------------------------------= + + /// A collection of unsigned integers. + /// + /// It must be `nonempty` at the start and end of each access. + /// + @usableFromInline var elements: Elements + + //=----------------------------------------------------------------= + // MARK: Initializers + //=----------------------------------------------------------------= + + @inlinable init(_ elements: Elements) { + self.elements = elements + precondition(!self.elements.isEmpty) + } + + @inlinable init(nonemptying elements: Elements) { + self.elements = elements + if self.elements.isEmpty { + self.elements.append(0) + } + } + + @inlinable init(unchecked elements: Elements) { + self.elements = elements + Swift.assert(!self.elements.isEmpty) + } + } + } +} + +//=----------------------------------------------------------------------------= +// MARK: + Details +//=----------------------------------------------------------------------------= + +extension IntXLOrUIntXL { + + //=------------------------------------------------------------------------= + // MARK: Utilities + //=------------------------------------------------------------------------= + + /// A `description` of this type. + /// + /// ``` + /// ┌─────────────────────────── → ────────────┐ + /// │ type │ description │ + /// ├─────────────────────────── → ────────────┤ + /// │ NBKFlexibleWidth │ "IntXL" │ + /// │ NBKFlexibleWidth.Magnitude │ "UIntXL" │ + /// └─────────────────────────── → ────────────┘ + /// ``` + /// + @inlinable public static var description: String { + Self.isSigned ? "IntXL" : "UIntXL" + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Aliases +//*============================================================================* + +/// A signed, flexible-width, integer. +/// +/// This name reserves a spot for a signed 2's-complement-in-memory integer. +/// +/// - Note: You can use `NBKSigned` until `IntXL` becomes available. +/// +public typealias IntXL = NBKFlexibleWidth + +/// An unsigned, flexible-width, integer. +public typealias UIntXL = NBKFlexibleWidth.Magnitude diff --git a/Sources/Numberick/Documentation.docc/Documentation.md b/Sources/Numberick/Documentation.docc/Documentation.md index 3456a435..46c64b13 100644 --- a/Sources/Numberick/Documentation.docc/Documentation.md +++ b/Sources/Numberick/Documentation.docc/Documentation.md @@ -96,6 +96,41 @@ Int256(5) % Int(5), UInt256(5) % UInt(5) - Note: You can use `StaticString` until `StaticBigInt` becomes available. +> [!IMPORTANT] +> It's a work in progress. I may rework it at any time. + +## NBKFlexibleWidthKit + +### Models + +- ``NBKFibonacciXL`` +- ``UIntXL`` + +### Fibonacci + +```swift +NBKFibonacciXL(0) // (index: 0, element: 0, next: 1) +NBKFibonacciXL(1) // (index: 1, element: 1, next: 1) +NBKFibonacciXL(2) // (index: 2, element: 1, next: 2) +NBKFibonacciXL(3) // (index: 3, element: 2, next: 3) +NBKFibonacciXL(4) // (index: 4, element: 3, next: 5) +NBKFibonacciXL(5) // (index: 5, element: 5, next: 8) +``` + +It uses a fast double-and-add algorithm: + +```swift +NBKFibonacciXL(10_000_000) // 2.3s on M1 MacBook Pro +``` + +But you can also step through it manually: + +```swift +public mutating func increment() { ... } // index + 1 +public mutating func decrement() { ... } // index - 1 +public mutating func double() { ... } // index * 2 +``` + ## Topics ### Protocols @@ -112,6 +147,7 @@ Int256(5) % Int(5), UInt256(5) % UInt(5) - ``NBKChunkedInt`` - ``NBKDoubleWidth`` - ``NBKEndianness`` +- ``NBKFlexibleWidth`` - ``NBKPrimeSieve`` - ``NBKStaticBigInt`` @@ -130,6 +166,7 @@ Int256(5) % Int(5), UInt256(5) % UInt(5) - ``UInt1024`` - ``UInt2048`` - ``UInt4096`` +- ``UIntXL`` ### Abbreviations diff --git a/Sources/Numberick/Exports.swift b/Sources/Numberick/Numberick.swift similarity index 100% rename from Sources/Numberick/Exports.swift rename to Sources/Numberick/Numberick.swift diff --git a/Tests/NBKCoreKitTests/NBKCoreInteger+Comparisons.swift b/Tests/NBKCoreKitTests/NBKCoreInteger+Comparisons.swift index b540d80f..303d9f09 100644 --- a/Tests/NBKCoreKitTests/NBKCoreInteger+Comparisons.swift +++ b/Tests/NBKCoreKitTests/NBKCoreInteger+Comparisons.swift @@ -211,9 +211,9 @@ final class NBKCoreIntegerTestsOnComparisons: XCTestCase { func testOverloadsAreUnambiguousWhenUsingSignum() { func becauseThisCompilesSuccessfully(_ x: inout some NBKCoreInteger, _ s: inout Int, _ u: inout UInt) { - XCTAssertNotNil(x.signum()) // Int - XCTAssertNotNil(s.signum()) // Int - XCTAssertNotNil(u.signum()) // UInt, stdlib + XCTAssertNotNil(x.signum()) + XCTAssertNotNil(s.signum()) + XCTAssertNotNil(u.signum()) } } } diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/Models/NBKFibonacciXL.swift b/Tests/NBKFlexibleWidthKitBenchmarks/Models/NBKFibonacciXL.swift new file mode 100644 index 00000000..fa75116f --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/Models/NBKFibonacciXL.swift @@ -0,0 +1,81 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x FibonacciXL +//*============================================================================* + +final class NBKFibonacciXLBenchmarks: XCTestCase { + + typealias T = NBKFibonacciXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testPrime222() { + var index = NBK.blackHoleIdentity(UInt(1399)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(T(index)) + NBK.blackHoleInoutIdentity(&index) + } + } + + func testPrime333() { + var index = NBK.blackHoleIdentity(UInt(2239)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(T(index)) + NBK.blackHoleInoutIdentity(&index) + } + } + + func testPrime555() { + var index = NBK.blackHoleIdentity(UInt(4019)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(T(index)) + NBK.blackHoleInoutIdentity(&index) + } + } + + func testPrime777() { + var index = NBK.blackHoleIdentity(UInt(5903)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(T(index)) + NBK.blackHoleInoutIdentity(&index) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x No Loop + //=------------------------------------------------------------------------= + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonacci+10000000 + /// + /// - Note: The 10,000,000th element contains 2,089,877 decimal digits. + /// + func testNoLoop10000000() { + NBK.blackHole(T(NBK.blackHoleIdentity(10_000_000))) + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Addition.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Addition.swift new file mode 100644 index 00000000..8310c55b --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Addition.swift @@ -0,0 +1,81 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Addition x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnAdditionAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testAdd() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs += rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testAdding() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs + rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testAddDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs += rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testAddingDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs + rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Bits.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Bits.swift new file mode 100644 index 00000000..cf7702f4 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Bits.swift @@ -0,0 +1,124 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Bits x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnBitsAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testInitBit() { + var abc = NBK.blackHoleIdentity(true ) + var xyz = NBK.blackHoleIdentity(false) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(T(bit: abc)) + NBK.blackHole(T(bit: xyz)) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testBitWidth() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.bitWidth) + NBK.blackHole(xyz.bitWidth) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testNonzeroBitCount() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.nonzeroBitCount) + NBK.blackHole(xyz.nonzeroBitCount) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testLeadingZeroBitCount() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.leadingZeroBitCount) + NBK.blackHole(xyz.leadingZeroBitCount) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testTrailingZeroBitCount() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.trailingZeroBitCount) + NBK.blackHole(xyz.trailingZeroBitCount) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testMostSignificantBit() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.mostSignificantBit) + NBK.blackHole(xyz.mostSignificantBit) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testLeastSignificantBit() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.leastSignificantBit) + NBK.blackHole(xyz.leastSignificantBit) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Comparisons.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Comparisons.swift new file mode 100644 index 00000000..e3bad654 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Comparisons.swift @@ -0,0 +1,150 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Comparisons x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnComparisonsAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testIsZero() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.isZero) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testIsLessThanZero() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.isLessThanZero) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testIsMoreThanZero() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.isMoreThanZero) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testIsPowerOf2() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.isPowerOf2) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testSignum() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.signum()) + NBK.blackHoleInoutIdentity(&abc) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testIsEqualTo() { + var lhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs == rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testIsLessThan() { + var lhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs < rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testComparedTo() { + var lhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs.compared(to: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testComparedToAtIndex() { + var lhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[1, 2, 3, 0] as X64)) + let xyz = NBK.blackHoleIdentity(1 as Int) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs.compared(to: rhs, at: xyz)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testComparedToDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs.compared(to: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testComparedToDigitAtIndex() { + var lhs = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt( 3)) + let xyz = NBK.blackHoleIdentity(3 as Int) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs.compared(to: rhs, at: xyz)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Complements.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Complements.swift new file mode 100644 index 00000000..248dfc37 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Complements.swift @@ -0,0 +1,160 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Complements x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnComplementsAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests x Magnitude + //=------------------------------------------------------------------------= + + func testMagnitude() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.magnitude) + NBK.blackHole(xyz.magnitude) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x One's Complement + //=------------------------------------------------------------------------= + + func testOnesComplement() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(abc.onesComplement()) + NBK.blackHole(xyz.onesComplement()) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testOnesComplementInout() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.formOnesComplement()) + NBK.blackHole(xyz.formOnesComplement()) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Two's Complement + //=------------------------------------------------------------------------= + + func testTwosComplement() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(abc.twosComplement()) + NBK.blackHole(xyz.twosComplement()) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testTwosComplementInout() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.formTwosComplement()) + NBK.blackHole(xyz.formTwosComplement()) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testTwosComplementReportingOverflow() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(abc.twosComplementReportingOverflow()) + NBK.blackHole(xyz.twosComplementReportingOverflow()) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + + func testTwosComplementReportingOverflowInout() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.formTwosComplementReportingOverflow()) + NBK.blackHole(xyz.formTwosComplementReportingOverflow()) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testTwosComplementSubsequence() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(abc.twosComplementSubsequence(true)) + NBK.blackHole(xyz.twosComplementSubsequence(true)) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } + + func testTwosComplementSubsequenceInout() { + var abc = NBK.blackHoleIdentity( T(x64:[0, 0, 0, 0] as X64)) + var xyz = NBK.blackHoleIdentity(~T(x64:[0, 0, 0, 0] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.formTwosComplementSubsequence(true)) + NBK.blackHole(xyz.formTwosComplementSubsequence(true)) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Division.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Division.swift new file mode 100644 index 00000000..528172bc --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Division.swift @@ -0,0 +1,152 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Division x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnDivisionAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testQuotientAndRemainder() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.quotientAndRemainder(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testQuotientReportingOverflow() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.dividedReportingOverflow(by: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testRemainderReportingOverflow() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.remainderReportingOverflow(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testQuotientAndRemainderDividingByDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.quotientAndRemainder(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testQuotientDividingByDigitReportingOverflow() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.dividedReportingOverflow(by: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testRemainderDividingByDigitReportingOverflow() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.remainderReportingOverflow(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Full Width + //=------------------------------------------------------------------------= + + func testDividingFullWidthAs256WhenDivisorIsNormalized() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0, ~1, ~0, ~0, ~0] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0] as X64)) // msb == true + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.quotientAndRemainder(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&rhs) + NBK.blackHoleInoutIdentity(&lhs) + } + } + + func testDividingFullWidthReportingOverflowAs256WhenDivisorIsNormalized() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0, ~1, ~0, ~0, ~0] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0] as X64)) // msb == true + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.quotientAndRemainderReportingOverflow(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&rhs) + NBK.blackHoleInoutIdentity(&lhs) + } + } + + func testDividingFullWidthAs256WhenDivisorIsNotNormalized() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0, ~1, ~0, ~0, ~0] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0/2] as X64)) // msb == false + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.quotientAndRemainder(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&rhs) + NBK.blackHoleInoutIdentity(&lhs) + } + } + + func testDividingFullWidthReportingOverflowAs256WhenDivisorIsNotNormalized() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0, ~1, ~0, ~0, ~0] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[~0, ~0, ~0, ~0/2] as X64)) // msb == false + + for _ in 0 ..< 250_000 { + NBK.blackHole(lhs.quotientAndRemainderReportingOverflow(dividingBy: rhs)) + NBK.blackHoleInoutIdentity(&rhs) + NBK.blackHoleInoutIdentity(&lhs) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Exponentiation.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Exponentiation.swift new file mode 100644 index 00000000..ef434ff1 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Exponentiation.swift @@ -0,0 +1,105 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Exponentiation x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnExponentiationAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func test2RaisedToPrime222() { + var base: T = NBK.blackHoleIdentity(T(000002)) + var exponent = NBK.blackHoleIdentity(Int(1399)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(base.power(exponent)) + NBK.blackHoleInoutIdentity(&base) + NBK.blackHoleInoutIdentity(&exponent) + } + } + + func test3RaisedToPrime333() { + var base: T = NBK.blackHoleIdentity(T(000003)) + var exponent = NBK.blackHoleIdentity(Int(2239)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(base.power(exponent)) + NBK.blackHoleInoutIdentity(&base) + NBK.blackHoleInoutIdentity(&exponent) + } + } + + func test5RaisedToPrime555() { + var base: T = NBK.blackHoleIdentity(T(000005)) + var exponent = NBK.blackHoleIdentity(Int(4019)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(base.power(exponent)) + NBK.blackHoleInoutIdentity(&base) + NBK.blackHoleInoutIdentity(&exponent) + } + } + + func test7RaisedToPrime777() { + var base: T = NBK.blackHoleIdentity(T(000007)) + var exponent = NBK.blackHoleIdentity(Int(5903)) + + for _ in 0 ..< 10_000 { + NBK.blackHole(base.power(exponent)) + NBK.blackHoleInoutIdentity(&base) + NBK.blackHoleInoutIdentity(&exponent) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x No Loop + //=------------------------------------------------------------------------= + + func testNoLoop5RaisedToPrime22222() { + let base: T = NBK.blackHoleIdentity(T(000002)) + let exponent = NBK.blackHoleIdentity(Int(252233)) + NBK.blackHole(base.power(exponent)) + } + + func testNoLoop5RaisedToPrime33333() { + let base: T = NBK.blackHoleIdentity(T(000003)) + let exponent = NBK.blackHoleIdentity(Int(393191)) + NBK.blackHole(base.power(exponent)) + } + + func testNoLoop5RaisedToPrime55555() { + let base: T = NBK.blackHoleIdentity(T(000005)) + let exponent = NBK.blackHoleIdentity(Int(686671)) + NBK.blackHole(base.power(exponent)) + } + + func testNoLoop7RaisedToPrime77777() { + let base: T = NBK.blackHoleIdentity(T(000007)) + let exponent = NBK.blackHoleIdentity(Int(989999)) + NBK.blackHole(base.power(exponent)) + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Logic.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Logic.swift new file mode 100644 index 00000000..fc4337fb --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Logic.swift @@ -0,0 +1,117 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Logic x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnLogicAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testNotInout() { + var abc = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(abc.formOnesComplement()) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testNot() { + var abc = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(~abc) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testAndInout() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs &= rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testAnd() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs & rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testOrInout() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs |= rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testOr() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs | rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testXorInout() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs ^= rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testXor() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs ^ rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Multiplication.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Multiplication.swift new file mode 100644 index 00000000..ba562634 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Multiplication.swift @@ -0,0 +1,73 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Multiplication x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnMultiplicationAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testMultiplying() { + var lhs = NBK.blackHoleIdentity(T(x64:[~1, ~2, ~3, ~4] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 1, 2, 3, 4] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs * rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testMultiplyingByDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[~1, ~2, ~3, ~4] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs * rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Square + //=------------------------------------------------------------------------= + + func testMultiplyingBySquaring() { + var base = NBK.blackHoleIdentity(T(x64:[~1, ~2, ~3, ~4] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(base.squared()) + NBK.blackHoleInoutIdentity(&base) + NBK.blackHoleInoutIdentity(&base) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Numbers.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Numbers.swift new file mode 100644 index 00000000..5a2d3cb2 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Numbers.swift @@ -0,0 +1,435 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Numbers x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnNumbersAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests x Constants + //=------------------------------------------------------------------------= + + @_optimize(none) + func makeInit() -> T { T( ) } + func testInit() { + for _ in 0 ..< 1_000_000 { + NBK.blackHole(makeInit()) + } + } + + @_optimize(none) + func makeZero() -> T { T.zero } + func testZero() { + for _ in 0 ..< 1_000_000 { + NBK.blackHole(makeZero()) + } + } + + @_optimize(none) + func makeOne() -> T { T.one } + func testOne() { + for _ in 0 ..< 1_000_000 { + NBK.blackHole(makeOne()) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Integers + //=------------------------------------------------------------------------= + + func testToInt() { + var abc = NBK.blackHoleIdentity(T(Int.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(Int(abc)) + NBK.blackHole(Int(exactly: abc)) + NBK.blackHole(Int(clamping: abc)) + NBK.blackHole(Int(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromInt() { + var abc = NBK.blackHoleIdentity(Int.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToUInt() { + var abc = NBK.blackHoleIdentity(T(UInt.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(UInt(abc)) + NBK.blackHole(UInt(exactly: abc)) + NBK.blackHole(UInt(clamping: abc)) + NBK.blackHole(UInt(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromUInt() { + var abc = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToInt8() { + var abc = NBK.blackHoleIdentity(T(Int8.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(Int8(abc)) + NBK.blackHole(Int8(exactly: abc)) + NBK.blackHole(Int8(clamping: abc)) + NBK.blackHole(Int8(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromInt8() { + var abc = NBK.blackHoleIdentity(Int8.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToUInt8() { + var abc = NBK.blackHoleIdentity(T(UInt8.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(UInt8(abc)) + NBK.blackHole(UInt8(exactly: abc)) + NBK.blackHole(UInt8(clamping: abc)) + NBK.blackHole(UInt8(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromUInt8() { + var abc = NBK.blackHoleIdentity(UInt8.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToInt16() { + var abc = NBK.blackHoleIdentity(T(Int16.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(Int16(abc)) + NBK.blackHole(Int16(exactly: abc)) + NBK.blackHole(Int16(clamping: abc)) + NBK.blackHole(Int16(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromInt16() { + var abc = NBK.blackHoleIdentity(Int16.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToUInt16() { + var abc = NBK.blackHoleIdentity(T(UInt16.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(UInt16(abc)) + NBK.blackHole(UInt16(exactly: abc)) + NBK.blackHole(UInt16(clamping: abc)) + NBK.blackHole(UInt16(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromUInt16() { + var abc = NBK.blackHoleIdentity(UInt16.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToInt32() { + var abc = NBK.blackHoleIdentity(T(Int32.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(Int32(abc)) + NBK.blackHole(Int32(exactly: abc)) + NBK.blackHole(Int32(clamping: abc)) + NBK.blackHole(Int32(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromInt32() { + var abc = NBK.blackHoleIdentity(Int32.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToUInt32() { + var abc = NBK.blackHoleIdentity(T(UInt32.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(UInt32(abc)) + NBK.blackHole(UInt32(exactly: abc)) + NBK.blackHole(UInt32(clamping: abc)) + NBK.blackHole(UInt32(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromUInt32() { + var abc = NBK.blackHoleIdentity(UInt32.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToInt64() { + var abc = NBK.blackHoleIdentity(T(Int64.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(Int64(abc)) + NBK.blackHole(Int64(exactly: abc)) + NBK.blackHole(Int64(clamping: abc)) + NBK.blackHole(Int64(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromInt64() { + var abc = NBK.blackHoleIdentity(Int64.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToUInt64() { + var abc = NBK.blackHoleIdentity(T(UInt64.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(UInt64(abc)) + NBK.blackHole(UInt64(exactly: abc)) + NBK.blackHole(UInt64(clamping: abc)) + NBK.blackHole(UInt64(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromUInt64() { + var abc = NBK.blackHoleIdentity(UInt64.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Complements + //=------------------------------------------------------------------------= + + func testToDigit() { + var abc = NBK.blackHoleIdentity(T(T.Digit.max)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(T.Digit(abc)) + NBK.blackHole(T.Digit(exactly: abc)) + NBK.blackHole(T.Digit(clamping: abc)) + NBK.blackHole(T.Digit(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromDigit() { + var abc = NBK.blackHoleIdentity(T.Digit.max) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(digit: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testToMagnitude() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 50_000 { + NBK.blackHole(M(abc)) + NBK.blackHole(M(exactly: abc)) + NBK.blackHole(M(clamping: abc)) + NBK.blackHole(M(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromMagnitude() { + var abc = NBK.blackHoleIdentity(M(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHole(T(clamping: abc)) + NBK.blackHole(T(truncatingIfNeeded: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Float + //=------------------------------------------------------------------------= + + // TODO: brrr + func testToFloat16() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000 { + NBK.blackHole(Float16(abc)) + NBK.blackHole(Float16(exactly: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromFloat16() { + var abc = NBK.blackHoleIdentity(Float16(123)) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + // TODO: brrr + func testToFloat32() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000 { + NBK.blackHole(Float32(abc)) + NBK.blackHole(Float32(exactly: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromFloat32() { + var abc = NBK.blackHoleIdentity(Float32(123)) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + // TODO: brrr + func testToFloat64() { + var abc = NBK.blackHoleIdentity(T(x64:[0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000 { + NBK.blackHole(Float64(abc)) + NBK.blackHole(Float64(exactly: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + func testFromFloat64() { + var abc = NBK.blackHoleIdentity(Float64(123)) + + for _ in 0 ..< 100_000 { + NBK.blackHole(T(abc)) + NBK.blackHole(T(exactly: abc)) + NBK.blackHoleInoutIdentity(&abc) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Sign & Magnitude + //=------------------------------------------------------------------------= + + func testSignAndMagnitude() { + var abc = NBK.blackHoleIdentity((sign: FloatingPointSign.plus, magnitude: M(x64:[0, 1, 2, 3] as X64))) + var xyz = NBK.blackHoleIdentity((sign: FloatingPointSign.minus, magnitude: M(x64:[0, 1, 2, 3] as X64))) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(T(sign: abc.sign, magnitude: abc.magnitude)) + NBK.blackHoleInoutIdentity(&abc) + + NBK.blackHole(T(sign: xyz.sign, magnitude: xyz.magnitude)) + NBK.blackHoleInoutIdentity(&xyz) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Shifts.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Shifts.swift new file mode 100644 index 00000000..916c786c --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Shifts.swift @@ -0,0 +1,152 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Shifts x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnShiftsAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests x Left + //=------------------------------------------------------------------------= + + func testBitShiftingLeft() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.bitWidth * 3/2) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs << rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testBitShiftingLeftByWords() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity((major: 1, minor: UInt.bitWidth/2)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftedLeft(major: rhs.major)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testBitShiftingLeftByWordsAndBits() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity((major: 1, minor: UInt.bitWidth/2)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftedLeft(major: rhs.major, minor: rhs.minor)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Right + //=------------------------------------------------------------------------= + + func testBitShiftingRight() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.bitWidth * 3/2) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs >> rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testBitShiftingRightByWords() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity((major: 1, minor: UInt.bitWidth/2)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftedRight(major: rhs.major)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testBitShiftingRightByWordsAndBits() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity((major: 1, minor: UInt.bitWidth/2)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftedRight(major: rhs.major, minor: rhs.minor)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x In Both Directions + //=------------------------------------------------------------------------= + + func testBitShiftingInBothDirectionsInout() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.bitWidth * 3/2) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftLeft (by: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + + NBK.blackHole(lhs.bitShiftRight(by: rhs)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testBitShiftingInBothDirectionsByWordsInout() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity((major: 1, minor: UInt.bitWidth/2)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftLeft (major: rhs.major)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + + NBK.blackHole(lhs.bitShiftRight(major: rhs.major)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testBitShiftingInBothDirectionsByWordsAndBitsInout() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity((major: 1, minor: UInt.bitWidth/2)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs.bitShiftLeft (major: rhs.major, minor: rhs.minor)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + + NBK.blackHole(lhs.bitShiftRight(major: rhs.major, minor: rhs.minor)) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Subtraction.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Subtraction.swift new file mode 100644 index 00000000..8fbfa337 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Subtraction.swift @@ -0,0 +1,81 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Subtraction x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnSubtractionAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testSubtract() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs -= rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testSubtracting() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(T(x64:[ 0, 1, 2, 3] as X64)) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs - rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testSubtractDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 5_000_000 { + NBK.blackHole(lhs -= rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } + + func testSubtractingDigit() { + var lhs = NBK.blackHoleIdentity(T(x64:[~0, ~1, ~2, ~3] as X64)) + var rhs = NBK.blackHoleIdentity(UInt.max) + + for _ in 0 ..< 1_000_000 { + NBK.blackHole(lhs - rhs) + NBK.blackHoleInoutIdentity(&lhs) + NBK.blackHoleInoutIdentity(&rhs) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Text.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Text.swift new file mode 100644 index 00000000..38290548 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Text.swift @@ -0,0 +1,110 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Text x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnTextAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: State + //=------------------------------------------------------------------------= + + static let decoded = NBK.blackHoleIdentity(T(encoded, radix: 16)!) + static let encoded = NBK.blackHoleIdentity(String(repeating: "1", count: 64)) + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testDecodingRadix10() { + var radix = NBK.blackHoleIdentity(10) + var encoded = NBK.blackHoleIdentity(Self.encoded) + + for _ in 0 ..< 250_000 { + NBK.blackHole(T(encoded, radix: radix)!) + NBK.blackHoleInoutIdentity(&radix) + NBK.blackHoleInoutIdentity(&encoded) + } + } + + func testDecodingRadix16() { + var radix = NBK.blackHoleIdentity(16) + var encoded = NBK.blackHoleIdentity(Self.encoded) + + for _ in 0 ..< 250_000 { + NBK.blackHole(T(encoded, radix: radix)!) + NBK.blackHoleInoutIdentity(&radix) + NBK.blackHoleInoutIdentity(&encoded) + } + } + + func testEncodingRadix10() { + var radix = NBK.blackHoleIdentity(10) + var decoded = NBK.blackHoleIdentity(Self.decoded) + + for _ in 0 ..< 250_000 { + NBK.blackHole(String(decoded, radix: radix)) + NBK.blackHoleInoutIdentity(&radix) + NBK.blackHoleInoutIdentity(&decoded) + } + } + + func testEncodingRadix16() { + var radix = NBK.blackHoleIdentity(16) + var decoded = NBK.blackHoleIdentity(Self.decoded) + + for _ in 0 ..< 250_000 { + NBK.blackHole(String(decoded, radix: radix)) + NBK.blackHoleInoutIdentity(&radix) + NBK.blackHoleInoutIdentity(&decoded) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Swift Standard Library Methods + //=------------------------------------------------------------------------= + + func testEncodingUsingSwiftStdlibRadix10() { + var radix = NBK.blackHoleIdentity(10) + var decoded = NBK.blackHoleIdentity(Self.decoded) + + for _ in 0 ..< 1_000 { + NBK.blackHole(String(NBK.someSwiftBinaryInteger(decoded), radix: radix)) + NBK.blackHoleInoutIdentity(&radix) + NBK.blackHoleInoutIdentity(&decoded) + } + } + + func testEncodingUsingSwiftStdlibRadix16() { + var radix = NBK.blackHoleIdentity(16) + var decoded = NBK.blackHoleIdentity(Self.decoded) + + for _ in 0 ..< 1_000 { + NBK.blackHole(String(NBK.someSwiftBinaryInteger(decoded), radix: radix)) + NBK.blackHoleInoutIdentity(&radix) + NBK.blackHoleInoutIdentity(&decoded) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Words.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Words.swift new file mode 100644 index 00000000..0cbb4e6a --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth+Words.swift @@ -0,0 +1,46 @@ +//=----------------------------------------------------------------------------= +// 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 NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Words x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthBenchmarksOnWordsAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testFromWords() { + var abc = NBK.blackHoleIdentity([ 0, 0, 0, 0] as X) + var xyz = NBK.blackHoleIdentity([~0, ~0, ~0, ~0] as X) + + for _ in 0 ..< 250_000 { + NBK.blackHole(T(words: abc)) + NBK.blackHole(T(words: xyz)) + + NBK.blackHoleInoutIdentity(&abc) + NBK.blackHoleInoutIdentity(&xyz) + } + } +} + +#endif diff --git a/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth.swift b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth.swift new file mode 100644 index 00000000..cabd8fa2 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitBenchmarks/NBKFlexibleWidth.swift @@ -0,0 +1,42 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x UIntXL +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + static let min256 = Self(x64:[ 0, 0, 0, 0] as X64) + static let max256 = Self(x64:[~0, ~0, ~0, ~0] as X64) + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + init(x32: [UInt32]) { + self.init(words: NBKChunkedInt(x32)) + } + + init(x64: [UInt64]) { + self.init(words: NBKChunkedInt(x64)) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/Models/NBKFibonacciXL.swift b/Tests/NBKFlexibleWidthKitTests/Models/NBKFibonacciXL.swift new file mode 100644 index 00000000..f2973551 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/Models/NBKFibonacciXL.swift @@ -0,0 +1,671 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x FibonacciXL +//*============================================================================* + +final class NBKFibonacciXLTests: XCTestCase { + + typealias T = NBKFibonacciXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testInit() { + XCTAssertEqual(T().index, 0 as UInt) + XCTAssertEqual(T().element, 0 as UIntXL) + XCTAssertEqual(T().next, 1 as UIntXL) + } + + func testStartSequence() { + NBKAssertFibonacciSequenceElement(0 as UInt, 0 as UIntXL) + NBKAssertFibonacciSequenceElement(1 as UInt, 1 as UIntXL) + NBKAssertFibonacciSequenceElement(2 as UInt, 1 as UIntXL) + NBKAssertFibonacciSequenceElement(3 as UInt, 2 as UIntXL) + NBKAssertFibonacciSequenceElement(4 as UInt, 3 as UIntXL) + NBKAssertFibonacciSequenceElement(5 as UInt, 5 as UIntXL) + } + + func testEachElementInUInt256() { + self.continueAfterFailure = false + + var fibonacci = T(); while fibonacci.next <= UIntXL.max256 { + NBKAssertFibonacciSequenceElement(fibonacci.index, fibonacci.element) + fibonacci.increment() + } + + XCTAssertEqual(fibonacci.index, 370 as UInt) + XCTAssertEqual(fibonacci.element, UIntXL("094611056096305838013295371573764256526437182762229865607320618320601813254535")) + XCTAssertEqual(fibonacci.next, UIntXL("153083904475345790698149223310665389766178449653686710164582374234640876900329")) + } +} + +//*============================================================================* +// MARK: * NBK x FibonacciXL x Primes +//*============================================================================* + +final class NBKFibonacciXLTestsOnPrimes: XCTestCase { + + typealias T = NBKFibonacciXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+1399 + func testPrime0222() { + NBKAssertFibonacciSequenceElement(UInt(1399), UIntXL(""" + 0000000000000000000000000001057362022138877586442790693627392471\ + 4349424343122542609372806319825783387389898145491654340696207977\ + 9703100859330541842708747836587076026853149515123668038994257349\ + 6825711057526259113835863240488302877201171798455616630015796594\ + 0742927387906176446848324713233936084752836275187153808643885101 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+2239 + func testPrime0333() { + NBKAssertFibonacciSequenceElement(UInt(2239), UIntXL(""" + 0000000000000000000000000000000000000000000037483619230023616383\ + 1556956012890801755635223834456440078068598512042225565858378705\ + 2775478508439311765008270803174379457823903626436917896144175108\ + 1812500769712739265577812142790633886426904029644292656072176594\ + 5442661544462371162680745392064002681693236118751836449122772276\ + 7869284859173664595855541705821814253059049650198752630703006217\ + 8339242653834274827433371972683579086589883072059016299647032544\ + 7184786711538554743189201957494849217103385151192357985565557661 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+4019 + func testPrime0555() { + NBKAssertFibonacciSequenceElement(UInt(4019), UIntXL(""" + 0000000000000000000000000000000000000000000000000000000037311367\ + 1412705742029424968910639277549742521996080310155045098365714482\ + 4104908347036042361244599159615512769990330987960639730865498130\ + 8072433775788325161992682362256795449665494209753670942172171272\ + 2203967369999425701889153758837814681835559585933723133751806881\ + 8496872580801685513615393162520513116429805804142523379378342551\ + 4441029659216936210529080660370851401177631514342389875828339972\ + 6614842546459415022870946655707302191026328812740600578177639873\ + 3039042717454551010941945840815871118048005931668653125862093108\ + 8958611234123487217337182078176768683790720523395222453566084951\ + 4492498420355556195880899437692737868135183556431736743842980245\ + 8400475635400414549626879469797956177065259238066131421408862659\ + 3874545400735945578330890239131064772372045179036218495472538674\ + 0316671667949438060397052349819774423263628326505983968411352681 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+5903 + func testPrime0777() { + NBKAssertFibonacciSequenceElement(UInt(5903), UIntXL(""" + 0000000000000000000000000000000000000000000000201630112973699547\ + 8467033798246231765802235127399927076436839763410065672009048903\ + 1282893541236712535277172854664465524821928062556461511462472243\ + 6645751603027750072868408113686717270843656386576571239706531613\ + 8832607318277041589340170938439083061589073645207050078640037387\ + 3930944738614316892092679585355923400727053939446917720844859420\ + 8475286500719315637423740931654098191825715510224786132537906089\ + 2798464444270756081302801050898869097388615552432632699803372579\ + 5006266664207612795271656344222004200834104891232199115031529879\ + 2703171846839972134549632698690061406266150782100519904238693642\ + 7990494803652598109479923921411786233223630306244612906702729633\ + 0936722357821751129503986058477775784943438980499220967251871125\ + 8907675708863225870261545152179027647035709552484493259087293234\ + 3560027918334679621500613235053762398727366706896356186229959919\ + 9113456220990739086184934440183082123185220867952003388928951448\ + 6862918684679538218518939139423048219131427786458175412165472787\ + 2317940678177228138520687104044551650142781207251510823550422463\ + 0550656054019863500046679727553797345950068888003234780117695468\ + 5001758459948949898864934140668770688345102830949505991111324318\ + 0359205788328847352554207256070124136434254282285393279119106977 + """)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+8933 + func testPrime1111() { + NBKAssertFibonacciSequenceElement(UInt(8933), UIntXL(""" + 0000000000000000000000000000000000000000000000000000034443347309\ + 3108100398874159428561534329862460467290782292059374507023810687\ + 7269550645425648759105040052746760332244524364798820376920762224\ + 6877914631058402796663109018927768541957271790876482142932617519\ + 8232710764202658059416769653472274254504964579687081297720007624\ + 6179906590303417326957815996792319972853675080055992845348080638\ + 2943941858852559981242264436155281348871852261317229982765011629\ + 7829399867445887010318141926897940016990199464221680611301721448\ + 4111880877333055360925677292547757377288269228562446803652009867\ + 7763837424235481301902728930839496921587048869618933660929975972\ + 1517514025501625973594302218805499993099572559531211120925573758\ + 1127211049766617087652687605434077686156615302804722142642742969\ + 7236516259493575568417191119601844734416138650251441687029645552\ + 9378027338036524313972052854242021568214636821793074375945751372\ + 2350735288210709662405496337371540441013444112061964378877977540\ + 7320833770153605816578141282892535002595557200364506492670167145\ + 0726828768210402995804992032894376632638787592193974240697731462\ + 4173426093112813331117064297373474850946738192421094692055974066\ + 8615304600181591587016350586791290544589827230483506166379140081\ + 1359202761416259334768284612565771296621865315396703987992963690\ + 0711808907302535316355004671178400195617638079207154035431579923\ + 6275073657060236813235586961734223575624017690360671164251634053\ + 7904112899667901706234971327433315032760833359348656741794825127\ + 0980333914295583912406671914635480194147780346368616686315693921\ + 1960544365157853401078146277796468432978786175071982645306456832\ + 5121277937989335078738684451639804479205134375476415837785960261\ + 3072720886334722185655615819938336831138028603969967045606920077\ + 3923425088074927054057487079424507914976894990682897213726723706\ + 5641602992393369968566546050746410960720492622663285722794807997\ + 8311465295401210944930675482964391010652349529256594693184486853 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+10781 + func testPrime1313() { + NBKAssertFibonacciSequenceElement(UInt(10781), UIntXL(""" + 0000000000000000000000000000000000000000000000000005575252393938\ + 9726472552878851686358361695118909953805835298368747083115480810\ + 4134206858282412439295319058881607250949303773993738147379991278\ + 9066389219619830310354918122704287612505372628737469127809777201\ + 1813475701346979469009944172420144596984822494955177372023557647\ + 4043326938010670966508892540357298492565956868756293339723701132\ + 8404250750366560095531400297763195438809085759814739595820309501\ + 9617565922583583797982866665243330079239109282604215784965687742\ + 3199127537109325220857944750281898171470259778544608936346797087\ + 6915506943706869360771458402127275793501020646387627407249104762\ + 2204554630802927208583175306259630935067305208225373494361458800\ + 7096186599980318811061789356312606910681403036416628463971243044\ + 9676454542542605700855087919781107617713561430014113975722279770\ + 1943126909722546119017203186665120360983636830415022614609397450\ + 9604753707365780210044755881283263888107066377496681747347015615\ + 8514085822105828425523508374621670793710046241937432728541155733\ + 0914849674581293014372528590738903198794885095978076379182211356\ + 8850732564285080127893430205879638079510183584289648061314690419\ + 5135955596853796607943727322148752306247174590234861143822254810\ + 6951078192204608500403919930122086472602505237928300102314072907\ + 7179369160802122078897866161437057394653943417426366481490741361\ + 4289364844639936935015401554938898120880039903185920895379153050\ + 8680984989744643618836532812439328568169858429217482962734527536\ + 2112218628051472668046326964948590305480267978383608888402781258\ + 4039624434468498804953615649454730516079195626785256716449895062\ + 0683281068232871339690528745784450361412639047835817184698747525\ + 1330839429557363015356657024930499413609803572635586116589269321\ + 5854296106351102291227895539398459227240334326466881685777618726\ + 1211503678186890387085065010835399785997747697962920002395011222\ + 7618727367561167800274149949254487497443976531205358384475040120\ + 0086277177318594857580065894215493599194537309040684176552912227\ + 4788426089916667312131905399172381261820691014127614124391607030\ + 8838007479628295381664256933648759302881044342226521123067649434\ + 5341174643126781104974171560230306840526654475870921746361461904\ + 5207826330444519833981042764782664689188565204047957279550140376\ + 2211505037201946054045566600359608592562206893317574720788556981 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+14657 + func testPrime1717() { + NBKAssertFibonacciSequenceElement(UInt(14657), UIntXL(""" + 0000000006058402761451576720258256337477128057826862985648553231\ + 7792747364397931841629915181414279266064883024426628396291466122\ + 9177123797344399944935353883040192213562607370370942801296415674\ + 4831940815115011704522807000416123941229043159865494449768268284\ + 5213015343812477344582968345381553774862654915281304146488339229\ + 0905751577864480452631488961486944090768718671777277058341949909\ + 0598213463184153769971728000572922970601922048947523233477633862\ + 4605940117480893067776137041766096080844967004804117122804759466\ + 9006105930886794316120039824717802748443209168568841074845662889\ + 6935726413247146161916158962195833997261590008433017661414179268\ + 1831524200571257483454283270201487522745985204231016858721168376\ + 4204838424490224992687215838073324412818476492336363527595903974\ + 2632201125470648063465602204008209868358340208238831880244894853\ + 8380938703087695071958351874730216254209174189928645314880310832\ + 4775157435083240983288867292037332127832230384192457617428710419\ + 0419438440074229054876357310667903268539675182119923471421252525\ + 6537262552593093479745468473830739848278865552686343702365989517\ + 3773211134129308445785053068898808762947645265952573217355793055\ + 4850102686805811390241068600401491893717026095251537359730169457\ + 3990081744311735200080667940019786365915959821622418269801682716\ + 6596659992783767880986211139881334245693235383082252465376547092\ + 4771719305421775423979399445370163126666135411541089674859434142\ + 1835346304339925212842839556354290754209070463222830249340248293\ + 1739993696040883790380813459754972316938279665637020715849857092\ + 5061700639938106659144053614097794348042880102707047616330867299\ + 6973292470394688344839778152623436816659227595915321227938328341\ + 8695229413388365284802370295539401105001856037640545023329968983\ + 9720520624847273775288825663411466903136750790075145785096609543\ + 1363277499484940003702951321364758335635842013672725717191372841\ + 0065626488944560040624474939147969708428874923902611421399953582\ + 2200268101256765961743964970550205355001268110188839226049677505\ + 1623087002378031163767895174628090371966482440348951525466700490\ + 0306839887785292558258342701095931995686366367559877732669332257\ + 1358756356346230890933338073842405693054665848682078025407632677\ + 2620470192165802011259487595954200797717773358315419964815372299\ + 6195409587630063775068328208088024558415834252378093842892718929\ + 2299135473848125337595320340087904453745452079513158053622971165\ + 4085240406291974087797856713448420777479401406754652943183985557\ + 8868203699337170872194994288252608754978892688426536497188510815\ + 7364026610714838180779459845051488817988582107375830890363050042\ + 7853429696042257522758180430172108630956409978805438863836933092\ + 4739581146926696299593021918958476990679847201833345597311390365\ + 9880670405236266277006690355879105629282009156334550051866396408\ + 4563190559147446283063349456439801769070355604620364159336926897\ + 0285743171597680332987690386608022606450622931003173519957475251\ + 4421556793365867802583688605873620149902834626905930182703487959\ + 5789919592472269185943875384292090665220487632998608535326665307\ + 8322112917847080756064230443788370332329358816888052386921588637 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+16573 + func testPrime1919() { + NBKAssertFibonacciSequenceElement(UInt(16573), UIntXL(""" + 0000000000000000000000000000000000000000000000000000000015946921\ + 6595804360171148324186170504700247087490619017724032457673189638\ + 8406563053857414743464065246822667413694564519388262483902542550\ + 7304199719296116967907455494069941402609496025287503400080249071\ + 6799346748096884891511650411342902626468451568408085175737224043\ + 2011547064434093596081413407194809084531412469158235626097079599\ + 4544081817757745947896950418000988242770836363338053376657871411\ + 5598616012149116937365648815811675868069045756257264786759082574\ + 0379202988560687772450367294176341690396840950168827943190173803\ + 0245262792901909836914578777130937158419130954373312839400747264\ + 5070533130795934700564479352231707645378096502364456874575890898\ + 8514145855600850496027210479118770752496191274591554959033026411\ + 2683428749134631988657824553937667845055339118615142651449416358\ + 0905997624691969213616678439237042066477305009346447100369253689\ + 3688334565987554374777457109676502759096458814654042501912335167\ + 0706187390719630926967216257738013794523611050256116565490256231\ + 9891136290574443453074828513767742039568535613753300798420089272\ + 2225177115779689566506544422273288588262272759468906150468441359\ + 6397175089896071209509123875268939776743236620957310216529259099\ + 9141943426397131027691801550272209821018760599985945262861927406\ + 9308251190780234336125927386217187911053158496005341601648249672\ + 2401040493122812774460164272671061221091914763033925549937560394\ + 6559665230830369854910585292832139715324065034507736029138309482\ + 2312757918773899364634930497625081850227169787604737714651454450\ + 9516285672211250722561838052711443661737163391222573206800382956\ + 7402008355901388090106402658212300814840071046196772360719117469\ + 2048080216235350346456247064285220256191464017708412972063996814\ + 6429745908023111295091507078703296786049688925676540830776485849\ + 8883041472117433223264782663990220348815837747673458579856454849\ + 5335251858902496697861181020644338469215448158003546846387887720\ + 6220867940421580823312471707704810612356068290594335958731433012\ + 1118061742151671523996812265891356206632166854679526249246979861\ + 3021142197850694945274033708740840977830764209705180218500547661\ + 2848376395847006023633770283282925867961504875080994109763831607\ + 4976100239412235386231903470189894313193983807604929600270781698\ + 5940587113759076695652087202708375382498853097885759661720413638\ + 0416871332567363274357246862035836632999686071143579586707431914\ + 6323497245317108860950389361705272840388955884407740618983477580\ + 7383474742557888511327713349572157192934163695609946438231170881\ + 3006554862841085537945117214241498813126695273657866724995138310\ + 9635215524263847364177520635773276504929770202486144145429157848\ + 9992473449881488436645763988524107358640364006420973373647634965\ + 5593633484530004623163597754642695072841607023346144269903190617\ + 1135374869603116982074369621793523120568517217641298340701484950\ + 2187393346175963513942839492977354054626260629553898018255345302\ + 7810256629740526977349569945652764150426072332211130248793742077\ + 3544538993768616165897011514905274092992594416861406822603855795\ + 2394743069496689729862466445975464211441556129329994146357761647\ + 2115354949796735070148198059437109189897347204481506628002678173\ + 2388253133986778655734158089790160722730615407740177774172234257\ + 8539470039391426726890791083194639399663729497784731973506650313\ + 4775115288605677946764763407188650802066313549519177891446635219\ + 1824446395826617363149926246728983123254560252324359143500529411\ + 6050484096633397161792453290607298549620456797861688826608122173\ + 6904113918598297451117909653465245260904946566563300071924368393 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+20599 + func testPrime2323() { + NBKAssertFibonacciSequenceElement(UInt(20599), UIntXL(""" + 0000000000000000000000000000000000000000000000038629270537189582\ + 8529979283940967439802360646972098590319440271529768033095199302\ + 3758130241095668320321605582674812524751729038532342939005581191\ + 5852313415601963873313807646257614513607430604038480591636658114\ + 1034809220533683560162480040259978110450115585485701095831574534\ + 8471561702179686609282117307301726671811028923862563128730001136\ + 9304239549137433567835279117039665545538916392135319260847410090\ + 2940386106871226849989797761088211368775690846792535305626650069\ + 1533415222384985832067470926096962224231289193175887556360836199\ + 0109285065131116526146324009027018570107524189602680579137453274\ + 2933205017049164995462600901232880476529618822140951413684387115\ + 9688949251140022709919715928109411512245300615031816044721410980\ + 7971559673879717157410392220128393490438452527391110631654576188\ + 4870411289114651798946476748047091869685727271206997822805981066\ + 2547021123129285466142482836785305504602152938906455060953275327\ + 8769531288687749159393334553365369720237462193504816916687829598\ + 9027661606674579151684873036377173184232047504292671539128465465\ + 0186522318025302040007409175122452608233688868633543023529723749\ + 0971888303705851314806767584806479111949175713378702583909301852\ + 8660220367677156497008527761885684578246279285663550964684069232\ + 0485907013011203440597823338513181901298053888840395646765393453\ + 5020582849212564471509801252237360276763122153424515880682664287\ + 3560150188489961590551438617878910619974208909978145724909090884\ + 5925953690466207611034227801542453276207033245380240928462289197\ + 8829475552659578415438826807529621137018964571651029050940227311\ + 7815585849897001393958188039104380140895107981267235308324065396\ + 2643078917311865172638219233796967781193452109134743057757607085\ + 4471765406351026425518448983952031840112479488745855641116628217\ + 6083149225670926255802062023512988291943699194002057093162176484\ + 3836640836041252761384935127685044307659055293506159324674205902\ + 2883065376023512902493665587451139635468244701079910415450533837\ + 0167305370532653490899205762281435373738236077601729993676436172\ + 6674866708693149640601914370112017488386183001955416258646268328\ + 2906901681035907393036794860959587350357821360740107973168059353\ + 3170872158813005154474290054865866002216141712360701363139172433\ + 0529747633439789734038560043084297291611744800701049503511748434\ + 9444156654199694548372109881650026477209594077220020260569756967\ + 5043445683563434667094030181089841677385424941855473590669154876\ + 6825236552847508423728100327786148503950184495715149123915222188\ + 6778787577891909382358801159742037582097594000091774327237372615\ + 5591498100224308950722080362544301086324851065279058150374983047\ + 2827589535880653283965670177710328900386004750984407571799666441\ + 3219453034084247931456268333741886306507259754575478680923014795\ + 8614363552006832227029283595770467886199382519399364489861056266\ + 7986340478288414292633005943027983639213182610305303113333808723\ + 8400779440943492534930920184600153736932178875413016916496455813\ + 5498135579354763656230107008910688041759827922058978859885847163\ + 0750719599110541886157144516676995927968842277211309355808274430\ + 0668910903471153895173322232355242398046349540749419513122447306\ + 6658126222411522666207534858164122644659029739492990081078684082\ + 6121266744156663272350313936440364720678062596818917231816899522\ + 9649077315298342777221433996905557076887765706883067250140289922\ + 5192861534495673788499741227523108269807892943116237351431048158\ + 0755253280887792830212019334930546287352187134551874072371496350\ + 8720370474391049174085392413004606230451803404142078245301869866\ + 4892198696913485731552705987761774062672086299266503956939315781\ + 4134704072796931626606350420407380476632203711249610433157983535\ + 1384037365043805017015082776423061625433070372211030610324502079\ + 9110067470790193838488239591139270050806272739561744343105080195\ + 2348749294062218463990587961262685832167406776602602069764912935\ + 4921350970937422748797177694783527787331244764255839670653311966\ + 7721173723947531865654195534587908167254630232634099620460933000\ + 9901467220096254677208328109791993173057095978938176526646955118\ + 8228881106631370547849087601431485580667108502650198015351349219\ + 4270994653050751095565020351346867793055017939430766649343635841\ + 1662647627156027266594751041143972594742023010783979073324611281\ + 8261495424248772493643391973322988200766709718376917562721443421\ + 9519587071569548532206502355071998611351304749711271360148537901 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+26701 + func testPrime2929() { + NBKAssertFibonacciSequenceElement(UInt(26701), UIntXL(""" + 0000000000000000000000000000000000000000000000000000675300875109\ + 0234929438935188767280246631646027578654026982038645465528096242\ + 6426996474228975105541687765656964644464830940747498280830235424\ + 2031931141315983895449752055136380893919950303539820327531101620\ + 2323189593857678229639471061837212968488832795060305066128998515\ + 2445222589631354303116100098854863447094244437516950303123502395\ + 7811396615552173086277729189481229809408599467176687856100006194\ + 7969077127677930835716725707618775449761944021527033983686650799\ + 9988087731537573011024600707801055375512747543846864759999924065\ + 2958073029512845206378900624995562864258599737308623622477253238\ + 8186098584753007173913613451418080366009539886828873030677793787\ + 7982127228538580063338262699017443471208292767123511696267977938\ + 2091911574911494559385017518987699777817738874124851335636343463\ + 0719718245175997014994650123235984840183738347325700287132440309\ + 9867793431848098411705271166520994119942825801684960993541327992\ + 5251617410899876800482194741477515315650005475068525751639218059\ + 2630927130982685361384388276077280415689988666423268720052925636\ + 8777451171993973468923935147019594244224567951532774834102103519\ + 0837813583038097773455105112435571915969507201823136759111647941\ + 4954739831339596799167107440954624894201928261844208892749739653\ + 6746563504906609912279484045721419585025746486562349031240589243\ + 9261329198015939592169562410200276565268453079450074540339805658\ + 0532671887528127138285602401002971508847229188004506116260113508\ + 6166941338624254832932090374110821271794318583083483957847495995\ + 9354370411266292990181075684281401846274131626936961931105802226\ + 7505927635502703620791200053191678670633318042194353285203267290\ + 3205605630954018852233111935939120632188848966702550914162445261\ + 3485367611377869467629761543171041065701947376143667672283621617\ + 1379896374342955109313828494473119703073536842954005919813718892\ + 9293448923804331513336315874960926375113726783218069971748978232\ + 8689172475158860462745842000801015715056111594971470366663513744\ + 9583379903964710607051122069597971659442255934402348272587217554\ + 8394606450928602526521721312354359827416772710839999198330627467\ + 5117190151873093526939557238129448125114838888372864471677900013\ + 7373465358389391070601474167847485357834842600025100061435000035\ + 6118692236540156850474258346560386044659291602724753363346027221\ + 6214776214735813888062836325054654731854820935551338353077967903\ + 1273137861831440355701385090237787410627837724347994297762941733\ + 0236512351320363240096525178652160905088032203529209418992899536\ + 9374132753839217901439580336383504454125598360345021349336681071\ + 0390647650373291213880191743067349193829649286747160993444344717\ + 5264107731694812332160327259326136668727385053253031879788204680\ + 7461416228497264133998678536204389046795624613828110266563220278\ + 5149356215859435473510727920261426099081592017011119881490982949\ + 7023002067918672955927247288112423248921694513909595985051779324\ + 2510994156667269945273260236165986445851612532840180037833644309\ + 6287077541685200981777064803899487501036559502525282228254456119\ + 1070901160881141716266743149826394630340530402812049953743614839\ + 1453051301477541050346069082267332209965825572194733939498323190\ + 6805275573138154604982233504548468589880423304091815383284186840\ + 4622453269660083577638544632983245866819326330825182471007540937\ + 6266379610250376797387686495628119067659573866025580059673234197\ + 3092096076361471214691352767311049682547119749441710063154411605\ + 2464352092562762618574849072183894921899200447333098289721754567\ + 6613537085944038622683256986075357990440020263586795913304178407\ + 2281241551493302396086632997070161892094522543349019684133169470\ + 1411396169175064042200135820562002633332956274662379683672737009\ + 0659838936593902163128256612055936132983075868995168279325418925\ + 3106250930810534147888030189042307533889462307566537998210781609\ + 4735153197852048437762899958854363099078007203923210820372467968\ + 0205152820984539492603757631679212082727454614930808036105060801\ + 0230559755035990248712761413957280222008813459677547690391469083\ + 7794820341867232071597403431754582488152407830261464122639385070\ + 0777590426863435094318682572063491344895252375919108079091965422\ + 0101836570561609174623912761337832806562009926210373911779575565\ + 3846743420381552582952183232516702798153821543049757862429733447\ + 8167977685956334813323632814926669247886262219116010252040716135\ + 2897476554437321847731075037020035950383432636877380402664896032\ + 3859995452660921611533114597164502351187600869360932289993346982\ + 9857582098882760846540869838953098184391294780120384390714682114\ + 7499075897874225530699995806316633267716891194856751810563006088\ + 0199330569871792460993720245786881303112584182110447094461058185\ + 1999662418366149061526459414555506619138784703963966348504827390\ + 6863305437623123933978422736834080969892805686986939655368293371\ + 3377706557487026685257764985326698628421445516074006706169110624\ + 5298802290663799157499089134769921914923358262532475599823761560\ + 4483958565750749610881185330992185908390338629113902548769952108\ + 6830869570653210304619977381319537655491467950816307059491892261\ + 6992211184254688699789622049795884156642882638561963607005739786\ + 1988378413519337958563166745062705487428149013040630091182073186\ + 0076828872368594441240747249984053770523742798762458130752166754\ + 7365349925062180430434115813625374893611576994970704106913918722\ + 4760334451852575331317506774408478687735110293441510713556834046\ + 2511699197541436392614083156255450622336998915690629623679934131\ + 8928863961997506076922372592718381989821863599401654547051603339\ + 7697379714496516685268486237901064126719277909321728995891868709\ + 1925542849216077868099431758658201762160604000606437802340205351\ + 9143234259377166658451685076865157931596415423153810612650692201 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=fibonnaci+28751 + func testPrime3131() { + NBKAssertFibonacciSequenceElement(UInt(28751), UIntXL(""" + 0000000179539422936879670273043077421513074187637090531654188941\ + 5741714251061429371751580439620520390780557350979774794868208366\ + 4166176620878272615316694300157066431179767088884468131326626406\ + 6006793087609312815351213411657546695669274095062698689154398219\ + 4273493634687995463092807527082580641615117429769927175041405435\ + 0295797490359697968749112307931392970248348413038891015623785621\ + 6088847611043512273516649762447035351619033256347137730401912564\ + 3331923459443385236632710033100206681972486278892253338953989812\ + 3946916355990491141327157042882267874194134287364062276578746447\ + 9906202330820336469762881009578044941150880449686894920299840694\ + 1491825760720059082900953382857229547427350359177762089685919844\ + 7618397959101638970146048426296929999043034632587960523515344559\ + 3760366379638998785266019668146381119294252066632685499014459540\ + 3228626661986220007077177536233318464572108992736543438403328805\ + 5574464598751322289974611560904876079017322893499933000150292780\ + 9314181521891997450492395408326917003309389028222204533522299269\ + 9642000490804899546448343060640047086553849375374919580904272499\ + 2861624797203649272053099350900207574531796666472086817602155859\ + 1726945528270185394184089768658379449840625960802021947544967032\ + 4466186751708025198780714921940794569731981222458468445510099036\ + 0443553766379370268117503080771639388168258715530538192587730633\ + 8011648767649780378020253215618980934849061793639902195268270484\ + 2839829671374952066915706595211206930317379946812934908158184018\ + 6632013950586228393873546910724730610623601482513609286385660089\ + 5583205661787583142839574359287019169878432307244569229200612045\ + 5315250627992995880563363584077006573129537285154494784466671567\ + 6932915680429008994407050765199142140297716924995768736291428740\ + 5659885583080498298853597502387982203742256599364832940936912262\ + 7306295914308130060217932216792472674883590412715203292872224381\ + 9052280939272105914017040234667970649280968676984639911487164048\ + 6950512688416085851306225825060523983737858111232273015386133906\ + 3067106584779968201933848186941851209943130293249538453239817040\ + 3166446141432467835847673289873984793187889019124685049346194236\ + 9012603600383131016803724007081968761885862426032848180961930077\ + 9950227963208023000595795424035960037191281549377793907086267841\ + 5354352203190660234784252410121708238590550542287009655613245108\ + 4416679066018355796949509138190703862193823826940976741589457419\ + 9842183809073744133600807601681164860417876735323999739439826648\ + 6396093302983871451192612904135076545912778407507119999762905951\ + 0904335217479313753450789666808129764725813866718422907715543747\ + 5344763133751758328696596023139757344616559598352109613358123372\ + 5336145288103713015016170797186814486644452292159678982593774509\ + 0858972188466104850594765553599721902079446786014336284406080746\ + 6047070155943090400227067832916854600535823815502930111708409043\ + 2646551842931647415209855009938485127601076223545576051292990210\ + 2073345189649748973785384281664653132841926472290823737428037653\ + 6301390966801847207486995822378225832339748068221848846740932398\ + 3959466133500499766954176307273566790793220329043374920481301689\ + 7354443162803012925024323638559444813297758478704463046749525448\ + 3994253427313816352373748756985250548695717403420035283611811551\ + 8903829328845718140654077721662950782418573463754497643481431064\ + 3444759787070706038677485548256120377130269594213530852587880736\ + 3063990392833728301764457275979490777842591550350013392734278293\ + 0393930894524284143461403246004295880475120230584716506627288175\ + 5954208405305936426750512693561765614064070467267484067260606449\ + 3160788244304650910047777206727593713757409794734146439721983067\ + 7409870968970884026847313052795953418080569240543747685844136978\ + 5225197858237765766397728263719405697355726278399445515930357298\ + 8820946469896191657334557780499195433494664378529806387436512888\ + 9384612665032347753991477348768850268462782942582242628537367484\ + 9666383666195546877373280285951667514644359014593205613661066790\ + 2637643008076793963393319103431361492547474087057096618104945092\ + 9068797079145859217618763638460930039892230437159663346142492177\ + 3487965404583123116632813844515253796490318415246151607418608028\ + 3165345513066792765071386479447739995779779804703780812619628392\ + 0818316702529642078660025202341533889455931013711373344622660581\ + 7998569624624648319474551095608887152210196761483059300431511310\ + 8382114269844714319724855109740243228740858105309781623648408010\ + 7923960983889953454879306942395750194186332543209679586920699011\ + 6488027814044240538940310045469339495606646708566622415099015800\ + 4029612595363304441617897449047010514432607944518064803360908350\ + 3221111187440030745261296906933672534423314714794484547420193048\ + 0822412634857367963841998731477632114802046883490061951648320782\ + 1113969713026065616413746693504606279025231159734952205068924264\ + 5445300445311422184567380131890416551079481518026600240603387378\ + 1342039627717709671407636367938362954081810163995396023446847021\ + 4631560420750186123322823291039949303888078407967268763717208095\ + 2543903864295730492482781564450746654358853202741987848049019427\ + 6997291932933637411541980129747240034390408819886320767106029202\ + 2157076256100758673195322200389179370252504774367560355559349336\ + 1421680232486838517875664644500753346409203626845922264415603503\ + 6600023866782527437887467155147365535405191710659008737894371890\ + 2544238762746656220809565535557780409118203706433673604351735361\ + 1800390642391766176484428020897344653285440131973888356373655223\ + 9957549790982938642228964935099790778423157577696154898603995912\ + 2480143799026707122818026432168253584012508348126651287673108845\ + 5775153316563617041325708734461855814522735925258064105229767393\ + 9788941361715571270608197036912192258301294845630182802656964927\ + 4745384928401986455586018549294785940736001683767865500630792096\ + 5443200185649550920854638482906746241812642506927742506108188194\ + 9878469667918098704628894843753687311207089697195422433354870257\ + 2096820521441917774150069112449092359767362686064167992531585299\ + 6612569833761373691337107507656423822097124691089029473989643597\ + 4231470719178170567974934919172609491675022209246170315053321249 + """)) + } +} + +//*============================================================================* +// MARK: * NBK x FibonacciXL x Assertions +//*============================================================================* + +private func NBKAssertFibonacciSequenceElement( +_ index: UInt, _ element: UIntXL, division: Bool = true, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + let x0 = NBKFibonacciXL(index + 0) + let x1 = NBKFibonacciXL(index + 1) + //=------------------------------------------= + XCTAssertEqual(x0.element, element, file: file, line: line) + XCTAssertEqual(x0.next, x1.element, file: file, line: line) + XCTAssertEqual(x1.next, x0.element + x1.element, file: file, line: line) + //=------------------------------------------= + increment: do { + var x = x0; x.increment() + XCTAssertEqual(x.index, x1.index, file: file, line: line) + XCTAssertEqual(x.element, x1.element, file: file, line: line) + XCTAssertEqual(x.next, x1.next, file: file, line: line) + } + + decrement: do { + var x = x1; x.decrement() + XCTAssertEqual(x.index, x0.index, file: file, line: line) + XCTAssertEqual(x.element, x0.element, file: file, line: line) + XCTAssertEqual(x.next, x0.next, file: file, line: line) + } + + double: do { + var x = NBKFibonacciXL(index / 2); x.double(); if index.isOdd { x.increment() } + XCTAssertEqual(x.index, x0.index, file: file, line: line) + XCTAssertEqual(x.element, x0.element, file: file, line: line) + XCTAssertEqual(x.next, x0.next, file: file, line: line) + } + + if division { + NBKAssertFibonacciSequenceDivisionInvariants(x0, NBKFibonacciXL(index / 2), file: file, line: line) + NBKAssertFibonacciSequenceDivisionInvariants(x0, NBKFibonacciXL(index / 3), file: file, line: line) + NBKAssertFibonacciSequenceDivisionInvariants(x0, NBKFibonacciXL(index / 5), file: file, line: line) + NBKAssertFibonacciSequenceDivisionInvariants(x0, NBKFibonacciXL(index / 7), file: file, line: line) + } +} + +private func NBKAssertFibonacciSequenceDivisionInvariants( +_ a: NBKFibonacciXL, _ b: NBKFibonacciXL, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + let c = NBKFibonacciXL(a.index - b.index) + let d = a.next.quotientAndRemainder(dividingBy: b.next) + //=------------------------------------------= + brr: do { var lhs: UIntXL, rhs: UIntXL + + lhs = b.element // f(b) + lhs *= c.element // f(c) + + rhs = d.quotient // f(a + 1) / f(b + 1) + rhs -= c.next // f(c + 1) + rhs *= b.next // f(b + 1) + rhs += d.remainder // f(a + 1) % f(b + 1) + + XCTAssertEqual(lhs, rhs, file: file, line: line) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Addition.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Addition.swift new file mode 100644 index 00000000..a9abc45d --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Addition.swift @@ -0,0 +1,121 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Addition x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnAdditionAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testAdding() { + NBKAssertAddition(T(0), T(0), Int(0), T(0)) + NBKAssertAddition(T(0), T(1), Int(0), T(1)) + NBKAssertAddition(T(0), T(2), Int(0), T(2)) + + NBKAssertAddition(T(1), T(0), Int(0), T(1)) + NBKAssertAddition(T(1), T(1), Int(0), T(2)) + NBKAssertAddition(T(1), T(2), Int(0), T(3)) + } + + func testAddingAtIndex() { + NBKAssertAddition(T(words:[ 0, 0, 0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[ 1, 2, 3, 0] as X)) + NBKAssertAddition(T(words:[~0, 0, 0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[ 0, 3, 3, 0] as X)) + NBKAssertAddition(T(words:[~0, ~0, 0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[ 0, 2, 4, 0] as X)) + NBKAssertAddition(T(words:[~0, ~0, ~0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[ 0, 2, 3, 1] as X)) + + NBKAssertAddition(T(words:[ 0, 0, 0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[ 0, 1, 2, 3] as X)) + NBKAssertAddition(T(words:[~0, 0, 0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[~0, 1, 2, 3] as X)) + NBKAssertAddition(T(words:[~0, ~0, 0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[~0, 0, 3, 3] as X)) + NBKAssertAddition(T(words:[~0, ~0, ~0, 0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[~0, 0, 2, 4] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testAddingDigit() { + NBKAssertAdditionByDigit(T(0), UInt(0), Int(0), T(0)) + NBKAssertAdditionByDigit(T(0), UInt(1), Int(0), T(1)) + NBKAssertAdditionByDigit(T(0), UInt(2), Int(0), T(2)) + + NBKAssertAdditionByDigit(T(1), UInt(0), Int(0), T(1)) + NBKAssertAdditionByDigit(T(1), UInt(1), Int(0), T(2)) + NBKAssertAdditionByDigit(T(1), UInt(2), Int(0), T(3)) + } + + func testAddingDigitAtIndex() { + NBKAssertAdditionByDigit(T(words:[ 0, 0, 0, 0] as X), UInt(3), Int(0), T(words:[ 3, 0, 0, 0] as X)) + NBKAssertAdditionByDigit(T(words:[~0, 0, 0, 0] as X), UInt(3), Int(0), T(words:[ 2, 1, 0, 0] as X)) + NBKAssertAdditionByDigit(T(words:[~0, ~0, 0, 0] as X), UInt(3), Int(0), T(words:[ 2, 0, 1, 0] as X)) + NBKAssertAdditionByDigit(T(words:[~0, ~0, ~0, 0] as X), UInt(3), Int(0), T(words:[ 2, 0, 0, 1] as X)) + + NBKAssertAdditionByDigit(T(words:[ 0, 0, 0, 0] as X), UInt(3), Int(1), T(words:[ 0, 3, 0, 0] as X)) + NBKAssertAdditionByDigit(T(words:[~0, 0, 0, 0] as X), UInt(3), Int(1), T(words:[~0, 3, 0, 0] as X)) + NBKAssertAdditionByDigit(T(words:[~0, ~0, 0, 0] as X), UInt(3), Int(1), T(words:[~0, 2, 1, 0] as X)) + NBKAssertAdditionByDigit(T(words:[~0, ~0, ~0, 0] as X), UInt(3), Int(1), T(words:[~0, 2, 0, 1] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x += 0) + XCTAssertNotNil(x.add(0, at: 0)) + + XCTAssertNotNil(x + 0) + XCTAssertNotNil(x.adding(0, at: 0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Addition x Assertions +//*============================================================================* + +private func NBKAssertAddition( +_ lhs: T, _ rhs: T, _ index: Int, _ partialValue: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if index.isZero { + XCTAssertEqual( lhs + rhs, partialValue, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs += rhs; return lhs }(), partialValue, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(lhs.adding(rhs, at: index), partialValue, file: file, line: line) + XCTAssertEqual({ var x = lhs; let _ = x.add(rhs, at: index); return x }(), partialValue, file: file, line: line) +} + +private func NBKAssertAdditionByDigit( +_ lhs: T, _ rhs: T.Digit, _ index: Int, _ partialValue: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if index.isZero { + XCTAssertEqual( lhs + rhs, partialValue, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs += rhs; return lhs }(), partialValue, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(lhs.adding(rhs, at: index), partialValue, file: file, line: line) + XCTAssertEqual({ var x = lhs; let _ = x.add(rhs, at: index); return x }(), partialValue, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Bits.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Bits.swift new file mode 100644 index 00000000..041744d5 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Bits.swift @@ -0,0 +1,95 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Bits x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnBitsAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testInitBit() { + XCTAssertEqual(T(bit: false), T( )) + XCTAssertEqual(T(bit: true ), T(1)) + } + + func testBitWidth() { + XCTAssertEqual(T(words:[ 0, 0, 0, 0] as X).bitWidth, UInt.bitWidth * 1) + XCTAssertEqual(T(words:[~0, ~0, ~0, ~0] as X).bitWidth, UInt.bitWidth * 4) + } + + func testNonzeroBitCount() { + XCTAssertEqual(T(words:[ 0, 0, 0, 0] as X).nonzeroBitCount, 0) + XCTAssertEqual(T(words:[ 1, 1, 1, 1] as X).nonzeroBitCount, 4) + } + + func testLeadingZeroBitCount() { + XCTAssertEqual(T(words:[ 0, 0, 0, 0] as X).leadingZeroBitCount, UInt.bitWidth * 1) + XCTAssertEqual(T(words:[~0, ~0, ~0, ~0] as X).leadingZeroBitCount, UInt.bitWidth * 0) + + XCTAssertEqual(T(words:[ 2, 0, 0, 0] as X).leadingZeroBitCount, UInt.bitWidth * 1 - 2) + XCTAssertEqual(T(words:[ 0, 2, 0, 0] as X).leadingZeroBitCount, UInt.bitWidth * 1 - 2) + XCTAssertEqual(T(words:[ 0, 0, 2, 0] as X).leadingZeroBitCount, UInt.bitWidth * 1 - 2) + XCTAssertEqual(T(words:[ 0, 0, 0, 2] as X).leadingZeroBitCount, UInt.bitWidth * 1 - 2) + } + + func testTrailingZeroBitCount() { + XCTAssertEqual(T(words:[ 0, 0, 0, 0] as X).trailingZeroBitCount, UInt.bitWidth * 1) + XCTAssertEqual(T(words:[~0, ~0, ~0, ~0] as X).trailingZeroBitCount, UInt.bitWidth * 0) + + XCTAssertEqual(T(words:[ 2, 0, 0, 0] as X).trailingZeroBitCount, UInt.bitWidth * 0 + 1) + XCTAssertEqual(T(words:[ 0, 2, 0, 0] as X).trailingZeroBitCount, UInt.bitWidth * 1 + 1) + XCTAssertEqual(T(words:[ 0, 0, 2, 0] as X).trailingZeroBitCount, UInt.bitWidth * 2 + 1) + XCTAssertEqual(T(words:[ 0, 0, 0, 2] as X).trailingZeroBitCount, UInt.bitWidth * 3 + 1) + } + + func testMostSignificantBit() { + XCTAssertEqual(T(words:[ 0, 0, 0, 0] as X).mostSignificantBit, false) + XCTAssertEqual(T(words:[~0, ~0, ~0, ~0] as X).mostSignificantBit, true ) + + XCTAssertEqual(T(words:[~0, 0, 0, 0] as X).mostSignificantBit, true ) + XCTAssertEqual(T(words:[ 0, ~0, 0, 0] as X).mostSignificantBit, true ) + XCTAssertEqual(T(words:[ 0, 0, ~0, 0] as X).mostSignificantBit, true ) + XCTAssertEqual(T(words:[ 0, 0, 0, ~0] as X).mostSignificantBit, true ) + + XCTAssertEqual(T(words:[~0, 1, 0, 0] as X).mostSignificantBit, false) + XCTAssertEqual(T(words:[ 0, ~0, 1, 0] as X).mostSignificantBit, false) + XCTAssertEqual(T(words:[ 0, 0, ~0, 1] as X).mostSignificantBit, false) + XCTAssertEqual(T(words:[ 1, 0, 0, ~0] as X).mostSignificantBit, true ) + } + + func testLeastSignificantBit() { + XCTAssertEqual(T(words:[ 0, 0, 0, 0] as X).leastSignificantBit, false) + XCTAssertEqual(T(words:[~0, ~0, ~0, ~0] as X).leastSignificantBit, true ) + + XCTAssertEqual(T(words:[~0, 0, 0, 0] as X).leastSignificantBit, true ) + XCTAssertEqual(T(words:[ 0, ~0, 0, 0] as X).leastSignificantBit, false) + XCTAssertEqual(T(words:[ 0, 0, ~0, 0] as X).leastSignificantBit, false) + XCTAssertEqual(T(words:[ 0, 0, 0, ~0] as X).leastSignificantBit, false) + + XCTAssertEqual(T(words:[~0, 1, 0, 0] as X).leastSignificantBit, true ) + XCTAssertEqual(T(words:[ 0, ~0, 1, 0] as X).leastSignificantBit, false) + XCTAssertEqual(T(words:[ 0, 0, ~0, 1] as X).leastSignificantBit, false) + XCTAssertEqual(T(words:[ 1, 0, 0, ~0] as X).leastSignificantBit, true ) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Comparisons.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Comparisons.swift new file mode 100644 index 00000000..4586a51f --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Comparisons.swift @@ -0,0 +1,279 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Comparisons x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnComparisonsAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testIsZero() { + XCTAssertTrue (T(words:[ 0] as X).isZero) + XCTAssertFalse(T(words:[ 1] as X).isZero) + XCTAssertFalse(T(words:[ 2] as X).isZero) + + XCTAssertFalse(T(words:[~0] as X).isZero) + XCTAssertFalse(T(words:[~1] as X).isZero) + XCTAssertFalse(T(words:[~2] as X).isZero) + } + + func testIsLessThanZero() { + XCTAssertFalse(T(words:[ 0] as X).isLessThanZero) + XCTAssertFalse(T(words:[ 1] as X).isLessThanZero) + XCTAssertFalse(T(words:[ 2] as X).isLessThanZero) + + XCTAssertFalse(T(words:[~0] as X).isLessThanZero) + XCTAssertFalse(T(words:[~1] as X).isLessThanZero) + XCTAssertFalse(T(words:[~2] as X).isLessThanZero) + } + + func testIsMoreThanZero() { + XCTAssertFalse(T(words:[ 0] as X).isMoreThanZero) + XCTAssertTrue (T(words:[ 1] as X).isMoreThanZero) + XCTAssertTrue (T(words:[ 2] as X).isMoreThanZero) + + XCTAssertTrue (T(words:[~0] as X).isMoreThanZero) + XCTAssertTrue (T(words:[~1] as X).isMoreThanZero) + XCTAssertTrue (T(words:[~2] as X).isMoreThanZero) + } + + func testIsOdd() { + XCTAssertFalse(T(words:[ 0] as X).isOdd) + XCTAssertTrue (T(words:[ 1] as X).isOdd) + XCTAssertFalse(T(words:[ 2] as X).isOdd) + + XCTAssertTrue (T(words:[~0] as X).isOdd) + XCTAssertFalse(T(words:[~1] as X).isOdd) + XCTAssertTrue (T(words:[~2] as X).isOdd) + } + + func testIsEven() { + XCTAssertTrue (T(words:[ 0] as X).isEven) + XCTAssertFalse(T(words:[ 1] as X).isEven) + XCTAssertTrue (T(words:[ 2] as X).isEven) + + XCTAssertFalse(T(words:[~0] as X).isEven) + XCTAssertTrue (T(words:[~1] as X).isEven) + XCTAssertFalse(T(words:[~2] as X).isEven) + } + + func testIsPowerOf2() { + XCTAssertFalse(T(words:[ 0] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 1] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 2] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 3] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 4] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 5] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 6] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 7] as X).isPowerOf2) + + XCTAssertFalse(T(words:[ 0, 0, 0, 0] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 1, 0, 0, 0] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 1, 1, 0, 0] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 0, 1, 0, 0] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 0, 1, 1, 0] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 0, 0, 1, 0] as X).isPowerOf2) + XCTAssertFalse(T(words:[ 0, 0, 1, 1] as X).isPowerOf2) + XCTAssertTrue (T(words:[ 0, 0, 0, 1] as X).isPowerOf2) + } + + func testSignum() { + NBKAssertSignum(T(words:[ 0] as X), Int(0)) + NBKAssertSignum(T(words:[ 1] as X), Int(1)) + NBKAssertSignum(T(words:[ 2] as X), Int(1)) + + NBKAssertSignum(T(words:[~0] as X), Int(1)) + NBKAssertSignum(T(words:[~1] as X), Int(1)) + NBKAssertSignum(T(words:[~2] as X), Int(1)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testHashing() { + var union = Set() + union.insert(T(words:[0, 0, 0, 0] as X)) + union.insert(T(words:[0, 0, 0, 0] as X)) + union.insert(T(words:[1, 0, 0, 0] as X)) + union.insert(T(words:[1, 0, 0, 0] as X)) + union.insert(T(words:[0, 1, 0, 0] as X)) + union.insert(T(words:[0, 1, 0, 0] as X)) + union.insert(T(words:[0, 0, 1, 0] as X)) + union.insert(T(words:[0, 0, 1, 0] as X)) + union.insert(T(words:[0, 0, 0, 1] as X)) + union.insert(T(words:[0, 0, 0, 1] as X)) + XCTAssertEqual(union.count, 5 as Int) + } + + func testComparing() { + NBKAssertComparisons(T(words:[0, 2, 3, 4] as X), T(words:[1, 2, 3, 4] as X), -Int(1)) + NBKAssertComparisons(T(words:[1, 0, 3, 4] as X), T(words:[1, 2, 3, 4] as X), -Int(1)) + NBKAssertComparisons(T(words:[1, 2, 0, 4] as X), T(words:[1, 2, 3, 4] as X), -Int(1)) + NBKAssertComparisons(T(words:[1, 2, 3, 0] as X), T(words:[1, 2, 3, 4] as X), -Int(1)) + NBKAssertComparisons(T(words:[0, 2, 3, 4] as X), T(words:[0, 2, 3, 4] as X), Int(0)) + NBKAssertComparisons(T(words:[1, 0, 3, 4] as X), T(words:[1, 0, 3, 4] as X), Int(0)) + NBKAssertComparisons(T(words:[1, 2, 0, 4] as X), T(words:[1, 2, 0, 4] as X), Int(0)) + NBKAssertComparisons(T(words:[1, 2, 3, 0] as X), T(words:[1, 2, 3, 0] as X), Int(0)) + NBKAssertComparisons(T(words:[1, 2, 3, 4] as X), T(words:[0, 2, 3, 4] as X), Int(1)) + NBKAssertComparisons(T(words:[1, 2, 3, 4] as X), T(words:[1, 0, 3, 4] as X), Int(1)) + NBKAssertComparisons(T(words:[1, 2, 3, 4] as X), T(words:[1, 2, 0, 4] as X), Int(1)) + NBKAssertComparisons(T(words:[1, 2, 3, 4] as X), T(words:[1, 2, 3, 0] as X), Int(1)) + } + + func testComparingAtIndex() { + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(0), Int(0)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(1), Int(0)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(2), Int(0)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(3), Int(0)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(4), Int(0)) + + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(0), -Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(1), -Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(2), -Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(3), -Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 0, 0, 0, 0, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(4), -Int(1)) + + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(0), Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(1), Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(2), Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(3), Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[0, 0, 0, 0] as X), Int(4), Int(1)) + + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(0), Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(1), Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(2), Int(0)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(3), -Int(1)) + NBKAssertComparisonsAtIndex(T(words:[0, 0, 1, 2, 3, 4, 0, 0] as X), T(words:[1, 2, 3, 4] as X), Int(4), -Int(1)) + } + + func testComparingByDigit() { + NBKAssertComparisonsByDigit(T(0), UInt(0), Int(0)) + NBKAssertComparisonsByDigit(T(1), UInt(1), Int(0)) + NBKAssertComparisonsByDigit(T(2), UInt(3), -Int(1)) + NBKAssertComparisonsByDigit(T(3), UInt(2), Int(1)) + + NBKAssertComparisonsByDigit(T(words:[0, 0, 0, 0]), UInt(1), -Int(1)) + NBKAssertComparisonsByDigit(T(words:[1, 0, 0, 0]), UInt(1), Int(0)) + NBKAssertComparisonsByDigit(T(words:[2, 0, 0, 0]), UInt(1), Int(1)) + + NBKAssertComparisonsByDigit(T(words:[0, 1, 0, 0]), UInt(1), Int(1)) + NBKAssertComparisonsByDigit(T(words:[1, 1, 0, 0]), UInt(1), Int(1)) + NBKAssertComparisonsByDigit(T(words:[2, 1, 0, 0]), UInt(1), Int(1)) + } + + func testComparingByDigitAtIndex() { + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(4), Int(0), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(4), Int(1), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(4), Int(2), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(4), Int(3), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(4), Int(4), -Int(1)) + + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(5), Int(0), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(5), Int(1), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(5), Int(2), Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(5), Int(3), -Int(1)) + NBKAssertComparisonsByDigitAtIndex(T(words:[1, 2, 3, 4]), UInt(5), Int(4), -Int(1)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguous() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x.signum()) + } + } + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x.compared(to: 0)) + XCTAssertNotNil(x.compared(to: 0, at: 0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Comparisons x Assertions +//*============================================================================* + +private func NBKAssertSignum( +_ operand: T, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(Int(operand.signum() as Int), signum, file: file, line: line) + XCTAssertEqual(Int(operand.signum() as T ), signum, file: file, line: line) // stdlib +} + +private func NBKAssertComparisons( +_ lhs: T, _ rhs: T, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs == rhs, signum == 0, file: file, line: line) + XCTAssertEqual(lhs != rhs, signum != 0, file: file, line: line) + + XCTAssertEqual(lhs < rhs, signum == -1, file: file, line: line) + XCTAssertEqual(lhs <= rhs, signum != 1, file: file, line: line) + + XCTAssertEqual(lhs > rhs, signum == 1, file: file, line: line) + XCTAssertEqual(lhs >= rhs, signum != -1, file: file, line: line) + + XCTAssertEqual(lhs.compared(to: rhs), signum, file: file, line: line) +} + +private func NBKAssertComparisonsAtIndex( +_ lhs: T, _ rhs: T, _ index: Int, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if index.isZero { + NBKAssertComparisons(lhs, rhs, signum, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(lhs.compared(to: rhs, at: index), signum, file: file, line: line) +} + +private func NBKAssertComparisonsByDigit( +_ lhs: T, _ rhs: T.Digit, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs == rhs, signum == 0, file: file, line: line) + XCTAssertEqual(lhs != rhs, signum != 0, file: file, line: line) + + XCTAssertEqual(lhs < rhs, signum == -1, file: file, line: line) + XCTAssertEqual(lhs <= rhs, signum != 1, file: file, line: line) + + XCTAssertEqual(lhs > rhs, signum == 1, file: file, line: line) + XCTAssertEqual(lhs >= rhs, signum != -1, file: file, line: line) + + XCTAssertEqual(lhs.compared(to: rhs), signum, file: file, line: line) +} + +private func NBKAssertComparisonsByDigitAtIndex( +_ lhs: T, _ rhs: T.Digit, _ index: Int, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if index.isZero { + NBKAssertComparisonsByDigit(lhs, rhs, signum, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(lhs.compared(to: rhs, at: index), signum, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Complements.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Complements.swift new file mode 100644 index 00000000..76815bf5 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Complements.swift @@ -0,0 +1,112 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Complements x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnComplementsAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests x Magnitude + //=------------------------------------------------------------------------= + + func testMagnitude() { + XCTAssertEqual(T(words:[ 1, 0, 0, 0] as X).magnitude, M(words:[ 1, 0, 0, 0] as X)) + XCTAssertEqual(T(words:[~0, 0, 0, 0] as X).magnitude, M(words:[~0, 0, 0, 0] as X)) + XCTAssertEqual(T(words:[ 1, 1, 1, 1] as X).magnitude, M(words:[ 1, 1, 1, 1] as X)) + XCTAssertEqual(T(words:[~0, ~0, ~0, ~0] as X).magnitude, M(words:[~0, ~0, ~0, ~0] as X)) + + XCTAssertEqual(T(magnitude: M(words:[ 1, 0, 0, 0] as X)), M(words:[ 1, 0, 0, 0] as X)) + XCTAssertEqual(T(magnitude: M(words:[~0, 0, 0, 0] as X)), M(words:[~0, 0, 0, 0] as X)) + XCTAssertEqual(T(magnitude: M(words:[ 1, 1, 1, 1] as X)), M(words:[ 1, 1, 1, 1] as X)) + XCTAssertEqual(T(magnitude: M(words:[~0, ~0, ~0, ~0] as X)), M(words:[~0, ~0, ~0, ~0] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x One's Complement + //=------------------------------------------------------------------------= + + func testOnesComplement() { + NBKAssertOnesComplement(T(words:[ 0, 0, 0, 0] as X), T(words:[~0, 0, 0, 0] as X)) + NBKAssertOnesComplement(T(words:[ 1, 0, 0, 0] as X), T(words:[~1, 0, 0, 0] as X)) + NBKAssertOnesComplement(T(words:[~0, 0, 0, 0] as X), T(words:[ 0, 0, 0, 0] as X)) + NBKAssertOnesComplement(T(words:[ 1, 1, 1, 1] as X), T(words:[~1, ~1, ~1, ~1] as X)) + NBKAssertOnesComplement(T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 0, 0, 0, 0] as X)) + + NBKAssertOnesComplement(T(words:[~0, ~0, ~0, ~0/2 + 0] as X), T(words:[ 0, 0, 0, ~0/2 + 1] as X)) + NBKAssertOnesComplement(T(words:[ 0, 0, 0, ~0/2 + 1] as X), T(words:[~0, ~0, ~0, ~0/2 + 0] as X)) + NBKAssertOnesComplement(T(words:[ 1, 0, 0, ~0/2 + 1] as X), T(words:[~1, ~0, ~0, ~0/2 + 0] as X)) + + NBKAssertOnesComplement(T(words:[ 1, 0, 0, ~0/2 + 1] as X), T(words:[~1, ~0, ~0, ~0/2 + 0] as X)) + NBKAssertOnesComplement(T(words:[ 0, 0, 0, ~0/2 + 1] as X), T(words:[~0, ~0, ~0, ~0/2 + 0] as X)) + NBKAssertOnesComplement(T(words:[~0, ~0, ~0, ~0/2 + 0] as X), T(words:[ 0, 0, 0, ~0/2 + 1] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Two's Complement + //=------------------------------------------------------------------------= + + func testTwosComplement() { + NBKAssertTwosComplement(T(words:[ 0, 0, 0, 0] as X), T(words:[ 0, 0, 0, 0] as X), true) + NBKAssertTwosComplement(T(words:[ 1, 0, 0, 0] as X), T(words:[~0, 0, 0, 0] as X)) + NBKAssertTwosComplement(T(words:[~0, 0, 0, 0] as X), T(words:[ 1, 0, 0, 0] as X)) + NBKAssertTwosComplement(T(words:[ 1, 1, 1, 1] as X), T(words:[~0, ~1, ~1, ~1] as X)) + NBKAssertTwosComplement(T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 1, 0, 0, 0] as X)) + + NBKAssertTwosComplement(T(words:[~0, ~0, ~0, ~0/2 + 0] as X), T(words:[ 1, 0, 0, ~0/2 + 1] as X)) + NBKAssertTwosComplement(T(words:[ 0, 0, 0, ~0/2 + 1] as X), T(words:[ 0, 0, 0, ~0/2 + 1] as X)) + NBKAssertTwosComplement(T(words:[ 1, 0, 0, ~0/2 + 1] as X), T(words:[~0, ~0, ~0, ~0/2 + 0] as X)) + + NBKAssertTwosComplement(T(words:[ 1, 0, 0, ~0/2 + 1] as X), T(words:[~0, ~0, ~0, ~0/2 + 0] as X)) + NBKAssertTwosComplement(T(words:[ 0, 0, 0, ~0/2 + 1] as X), T(words:[ 0, 0, 0, ~0/2 + 1] as X)) + NBKAssertTwosComplement(T(words:[~0, ~0, ~0, ~0/2 + 0] as X), T(words:[ 1, 0, 0, ~0/2 + 1] as X)) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Complements x Assertions +//*============================================================================* + +private func NBKAssertOnesComplement( +_ integer: T, _ result: T, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(integer.onesComplement(), result, file: file, line: line) + XCTAssertEqual(integer.twosComplementSubsequence(false).partialValue, result, file: file, line: line) + + XCTAssertEqual({ var x = integer; let _ = x.formOnesComplement(); return x }(), result, file: file, line: line) + XCTAssertEqual({ var x = integer; let _ = x.formTwosComplementSubsequence(false); return x }(), result, file: file, line: line) +} + +private func NBKAssertTwosComplement( +_ integer: T, _ partialValue: T, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(integer.twosComplement(), partialValue, file: file, line: line) + XCTAssertEqual(integer.twosComplementReportingOverflow().partialValue, partialValue, file: file, line: line) + XCTAssertEqual(integer.twosComplementReportingOverflow().overflow, overflow, file: file, line: line) + XCTAssertEqual(integer.twosComplementSubsequence(true ).partialValue, partialValue, file: file, line: line) + XCTAssertEqual(integer.twosComplementSubsequence(true ).overflow, overflow, file: file, line: line) + + XCTAssertEqual({ var x = integer; x.formTwosComplement(); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = integer; let _ = x.formTwosComplementReportingOverflow(); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = integer; let o = x.formTwosComplementReportingOverflow(); return o }(), overflow, file: file, line: line) + XCTAssertEqual({ var x = integer; let _ = x.formTwosComplementSubsequence(true ); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = integer; let o = x.formTwosComplementSubsequence(true ); return o }(), overflow, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift new file mode 100644 index 00000000..2350f371 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift @@ -0,0 +1,294 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Division x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnDivisionAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testDividing() { + NBKAssertDivision(T( ), T(1), T( ), T( )) + NBKAssertDivision(T( ), T(2), T( ), T( )) + NBKAssertDivision(T(7), T(1), T(7), T( )) + NBKAssertDivision(T(7), T(2), T(3), T(1)) + } + + func testDividingReportingOverflow() { + NBKAssertDivision(T( ), T( ), T( ), T( ), true) + NBKAssertDivision(T(1), T( ), T(1), T(1), true) + NBKAssertDivision(T(2), T( ), T(2), T(2), true) + } + + func testDividingWithLargeDividend() { + NBKAssertDivision(T(x64:[~2, ~4, ~6, 9] as X64), T(2), T(x64:[~1, ~2, ~3, 4] as X64), T(1)) + NBKAssertDivision(T(x64:[~3, ~6, ~9, 14] as X64), T(3), T(x64:[~1, ~2, ~3, 4] as X64), T(2)) + NBKAssertDivision(T(x64:[~4, ~8, ~12, 19] as X64), T(4), T(x64:[~1, ~2, ~3, 4] as X64), T(3)) + NBKAssertDivision(T(x64:[~5, ~10, ~15, 24] as X64), T(5), T(x64:[~1, ~2, ~3, 4] as X64), T(4)) + + NBKAssertDivision(T(x64:[~2, ~4, ~6, 9] as X64), T(x64:[~1, ~2, ~3, 4] as X64), T(2), T(1)) + NBKAssertDivision(T(x64:[~3, ~6, ~9, 14] as X64), T(x64:[~1, ~2, ~3, 4] as X64), T(3), T(2)) + NBKAssertDivision(T(x64:[~4, ~8, ~12, 19] as X64), T(x64:[~1, ~2, ~3, 4] as X64), T(4), T(3)) + NBKAssertDivision(T(x64:[~5, ~10, ~15, 24] as X64), T(x64:[~1, ~2, ~3, 4] as X64), T(5), T(4)) + } + + func testDividingWithLargeDivisor() { + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[ 3, 4, 5, 6 &+ 1 << 63] as X64), T(0), T(x64:[1, 2, 3, 4 + 1 << 63] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[ 2, 3, 4, 5 &+ 1 << 63] as X64), T(0), T(x64:[1, 2, 3, 4 + 1 << 63] as X64)) + + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[ 1, 2, 3, 4 &+ 1 << 63] as X64), T(1), T(x64:[0, 0, 0, 0] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[ 0, 1, 2, 3 &+ 1 << 63] as X64), T(1), T(x64:[1, 1, 1, 1] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[~0, ~0, 0, 2 &+ 1 << 63] as X64), T(1), T(x64:[2, 2, 2, 2] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[~1, ~1, ~0, 0 &+ 1 << 63] as X64), T(1), T(x64:[3, 3, 3, 3] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[~2, ~2, ~1, ~0 &+ 1 << 63] as X64), T(1), T(x64:[4, 4, 4, 4] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[~3, ~3, ~2, ~1 &+ 1 << 63] as X64), T(1), T(x64:[5, 5, 5, 5] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[~4, ~4, ~3, ~2 &+ 1 << 63] as X64), T(1), T(x64:[6, 6, 6, 6] as X64)) + NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X64), T(x64:[~5, ~5, ~4, ~3 &+ 1 << 63] as X64), T(1), T(x64:[7, 7, 7, 7] as X64)) + } + + func testDividingLikeFullWidth() { + var dividend: T + //=--------------------------------------= + dividend = T(words:[ 06, 17, 35, 61, 61, 52, 32, 00] as X) + NBKAssertDivision(dividend, T(words:[ 1, 2, 3, 4] as X), T(words:[ 5, 6, 7, 8] as X), T(words:[ 1, 1, 1, 1] as X)) + NBKAssertDivision(dividend, T(words:[ 5, 6, 7, 8] as X), T(words:[ 1, 2, 3, 4] as X), T(words:[ 1, 1, 1, 1] as X)) + //=--------------------------------------= + dividend = T(words:[ 34, 54, 63, 62, 34, 16, 05, 00] as X) + NBKAssertDivision(dividend, T(words:[ 4, 3, 2, 1] as X), T(words:[ 9, 7, 6, 5] as X), T(words:[~1, ~1, ~0, 0] as X)) + NBKAssertDivision(dividend, T(words:[ 8, 7, 6, 5] as X), T(words:[ 4, 3, 2, 1] as X), T(words:[ 2, 2, 2, 2] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit (and Self) + //=------------------------------------------------------------------------= + + func testDividingByDigit() { + NBKAssertDivisionByDigit(T( ), UInt(1), T( ), UInt( )) + NBKAssertDivisionByDigit(T( ), UInt(2), T( ), UInt( )) + NBKAssertDivisionByDigit(T(7), UInt(1), T(7), UInt( )) + NBKAssertDivisionByDigit(T(7), UInt(2), T(3), UInt(1)) + } + + func testDividingByDigitReportingOverflow() { + NBKAssertDivisionByDigit(T( ), UInt( ), T( ), UInt( ), true) + NBKAssertDivisionByDigit(T(1), UInt( ), T(1), UInt(1), true) + NBKAssertDivisionByDigit(T(2), UInt( ), T(2), UInt(2), true) + } + + func testDividingByDigitWithLargeDividend() { + NBKAssertDivisionByDigit(T(words:[~2, ~4, ~6, 9] as X), UInt(2), T(words:[~1, ~2, ~3, 4] as X), UInt(1)) + NBKAssertDivisionByDigit(T(words:[~3, ~6, ~9, 14] as X), UInt(3), T(words:[~1, ~2, ~3, 4] as X), UInt(2)) + NBKAssertDivisionByDigit(T(words:[~4, ~8, ~12, 19] as X), UInt(4), T(words:[~1, ~2, ~3, 4] as X), UInt(3)) + NBKAssertDivisionByDigit(T(words:[~5, ~10, ~15, 24] as X), UInt(5), T(words:[~1, ~2, ~3, 4] as X), UInt(4)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x /= 0) + XCTAssertNotNil(x %= 0) + XCTAssertNotNil(x.divideReportingOverflow(by: 0)) + XCTAssertNotNil(x.formRemainderReportingOverflow(dividingBy: 0)) + + XCTAssertNotNil(x / 0) + XCTAssertNotNil(x % 0) + XCTAssertNotNil(x.dividedReportingOverflow(by: 0)) + XCTAssertNotNil(x.remainderReportingOverflow(dividingBy: 0)) + XCTAssertNotNil(x.quotientAndRemainder(dividingBy: 0)) + XCTAssertNotNil(x.quotientAndRemainderReportingOverflow(dividingBy: 0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Division x UIntXL x Code Coverage +//*============================================================================* + +final class NBKFlexibleWidthTestsOnDivisionCodeCoverageAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testDividingFullWidth3212MSBAsUInt256() { + var dividend: T, divisor: T, quotient: T, remainder: T + //=--------------------------------------= + dividend = T(x64:[ 0, 0, 0, 0, 0, ~0, ~0, ~0] as X64) + divisor = T(x64:[~0, ~0, ~0, ~0, 0, 0, 0, 0] as X64) + quotient = T(x64:[ 0, ~0, ~0, ~0, 0, 0, 0, 0] as X64) + remainder = T(x64:[ 0, ~0, ~0, ~0, 0, 0, 0, 0] as X64) + NBKAssertDivision(dividend, divisor, quotient, remainder) + //=--------------------------------------= + dividend = T(x64:[~0, ~0, ~0, ~0, 0, ~0, ~0, ~0] as X64) + divisor = T(x64:[~0, ~0, ~0, ~0, 0, 0, 0, 0] as X64) + quotient = T(x64:[ 1, ~0, ~0, ~0, 0, 0, 0, 0] as X64) + remainder = T(x64:[ 0, ~0, ~0, ~0, 0, 0, 0, 0] as X64) + NBKAssertDivision(dividend, divisor, quotient, remainder) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Division x Assertions +//*============================================================================* + +private func NBKAssertDivision( +_ dividend: T, _ divisor: T, _ quotient: T, _ remainder: T, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if !overflow { + XCTAssertEqual(dividend, quotient * divisor + remainder, "dividend != divisor * quotient + remainder", file: file, line: line) + } + + if !overflow { + XCTAssertEqual(dividend / divisor, quotient, file: file, line: line) + XCTAssertEqual(dividend % divisor, remainder, file: file, line: line) + } + + if !overflow { + XCTAssertEqual({ var lhs = dividend; lhs /= divisor; return lhs }(), quotient, file: file, line: line) + XCTAssertEqual({ var lhs = dividend; lhs %= divisor; return lhs }(), remainder, file: file, line: line) + } + + if !overflow { + let out = dividend.quotientAndRemainder(dividingBy: divisor) + XCTAssertEqual(out.quotient, quotient, file: file, line: line) + XCTAssertEqual(out.remainder, remainder, file: file, line: line) + } + + brr: do { + let out = dividend.dividedReportingOverflow(by: divisor) + XCTAssertEqual(out.partialValue, quotient, file: file, line: line) + XCTAssertEqual(out.overflow, overflow, file: file, line: line) + } + + brr: do { + var lhs = dividend + let out = lhs.divideReportingOverflow(by: divisor) + XCTAssertEqual(lhs, quotient, file: file, line: line) + XCTAssertEqual(out, overflow, file: file, line: line) + } + + brr: do { + let out = dividend.remainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(out.partialValue, remainder, file: file, line: line) + XCTAssertEqual(out.overflow, overflow, file: file, line: line) + } + + brr: do { + var lhs = dividend + let out = lhs.formRemainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(lhs, remainder, file: file, line: line) + XCTAssertEqual(out, overflow, file: file, line: line) + } + + brr: do { + let pvo = dividend.quotientAndRemainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(pvo.partialValue.quotient, quotient, file: file, line: line) + XCTAssertEqual(pvo.partialValue.remainder, remainder, file: file, line: line) + XCTAssertEqual(pvo.overflow, overflow, file: file, line: line) + } +} + +private func NBKAssertDivisionByDigit( +_ dividend: T, _ divisor: T.Digit, _ quotient: T, _ remainder: T.Digit, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + let extended = T(digit: remainder) + //=------------------------------------------= + NBKAssertDivision(dividend, T(digit: divisor), quotient, T(digit: remainder), overflow, file: file, line: line) + //=------------------------------------------= + if !overflow { + XCTAssertEqual(dividend, quotient * divisor + remainder, "dividend != divisor * quotient + remainder", file: file, line: line) + } + + if !overflow { + XCTAssertEqual(dividend / divisor, quotient, file: file, line: line) + XCTAssertEqual(dividend % divisor, remainder, file: file, line: line) + } + + if !overflow { + XCTAssertEqual({ var lhs = dividend; lhs /= divisor; return lhs }(), quotient, file: file, line: line) + XCTAssertEqual({ var lhs = dividend; lhs %= divisor; return lhs }(), extended, file: file, line: line) + } + + if !overflow { + let out = dividend.quotientAndRemainder(dividingBy: divisor) + XCTAssertEqual(out.quotient, quotient, file: file, line: line) + XCTAssertEqual(out.remainder, remainder, file: file, line: line) + } + + brr: do { + let out = dividend.dividedReportingOverflow(by: divisor) + XCTAssertEqual(out.partialValue, quotient, file: file, line: line) + XCTAssertEqual(out.overflow, overflow, file: file, line: line) + } + + brr: do { + var lhs = dividend + let out = lhs.divideReportingOverflow(by: divisor) + XCTAssertEqual(lhs, quotient, file: file, line: line) + XCTAssertEqual(out, overflow, file: file, line: line) + } + + brr: do { + let out = dividend.remainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(out.partialValue, remainder, file: file, line: line) + XCTAssertEqual(out.overflow, overflow, file: file, line: line) + } + + brr: do { + var lhs = dividend + let out = lhs.formRemainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(lhs, extended, file: file, line: line) + XCTAssertEqual(out, overflow, file: file, line: line) + } + + brr: do { + let pvo = dividend.quotientAndRemainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(pvo.partialValue.quotient, quotient, file: file, line: line) + XCTAssertEqual(pvo.partialValue.remainder, remainder, file: file, line: line) + XCTAssertEqual(pvo.overflow, overflow, file: file, line: line) + } + + guard + let dividend = dividend as? UIntXL, + let divisor = divisor as? UInt, + let quotient = quotient as? UIntXL, + let remainder = remainder as? UInt + else { return precondition(T.isSigned) } + + brr: do { + var lhs = dividend + let pvo = lhs.formQuotientWithRemainderReportingOverflow(dividingBy: divisor) + XCTAssertEqual(lhs, quotient, file: file, line: line) + XCTAssertEqual(pvo.partialValue, remainder, file: file, line: line) + XCTAssertEqual(pvo.overflow, overflow, file: file, line: line) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Exponentiation.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Exponentiation.swift new file mode 100644 index 00000000..95ed38d6 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Exponentiation.swift @@ -0,0 +1,348 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Exponentiation x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnExponentiationAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests x Small Base + //=------------------------------------------------------------------------= + + func testPowersOf0() { + for exponent in 0 as Int ..< 10 { + NBKAssertExponentiation(T.zero, exponent, exponent.isZero ? T.one : T.zero) + } + } + + func testPowersOf1() { + for exponent in 0 as Int ..< 10 { + NBKAssertExponentiation(T.one, exponent, T.one) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Small Exponent + //=------------------------------------------------------------------------= + + func testBaseRaisedTo0ReturnsOne() { + func with(_ base: T) { + NBKAssertExponentiation(base, Int(0), T.one) + } + + for word in (-5 ... 5).lazy.map(UInt.init(bitPattern:)){ + with(T(words:[word ] as X)) + with(T(words:[word, word &- 1 ] as X)) + with(T(words:[word, word &- 1, word &+ 2 ] as X)) + with(T(words:[word, word &- 1, word &+ 2, word &* 3] as X)) + } + } + + func testBaseRaisedTo1IsBase() { + func with(_ base: T) { + NBKAssertExponentiation(base, Int(1), base) + } + + for word in (-5 ... 5).lazy.map(UInt.init(bitPattern:)){ + with(T(words:[word ] as X)) + with(T(words:[word, word &- 1 ] as X)) + with(T(words:[word, word &- 1, word &+ 2 ] as X)) + with(T(words:[word, word &- 1, word &+ 2, word &* 3] as X)) + } + } + + func testBaseRaisedTo2IsBaseSquared() { + func with(_ base: T) { + NBKAssertExponentiation(base, Int(2), base * base) + } + + for word in (-5 ... 5).lazy.map(UInt.init(bitPattern:)){ + with(T(words:[word ] as X)) + with(T(words:[word, word &- 1 ] as X)) + with(T(words:[word, word &- 1, word &+ 2 ] as X)) + with(T(words:[word, word &- 1, word &+ 2, word &* 3] as X)) + } + } + + func testBaseRaisedTo3IsBaseCubed() { + func with(_ base: T) { + NBKAssertExponentiation(base, Int(3), base * base * base) + } + + for word in (-5 ... 5).lazy.map(UInt.init(bitPattern:)){ + with(T(words:[word ] as X)) + with(T(words:[word, word &- 1 ] as X)) + with(T(words:[word, word &- 1, word &+ 2 ] as X)) + with(T(words:[word, word &- 1, word &+ 2, word &* 3] as X)) + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x.power(0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Exponentiation x UIntXL x Primes +//*============================================================================* + +final class NBKFlexibleWidthTestsOnExponentiationByPrimesAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5B2%2C1399%5D + func test2RaisedToPrime222() { + NBKAssertExponentiation(T(2), Int(1399), T(""" + 0000000000000000000000000013834514851379060073245971093437442064\ + 9160977983437969614705766643223075185306094487364790624541806526\ + 1469876608299964693394277268648930360258831509072633846696053692\ + 0615225071992089480779025598319909176616250787667116220112182629\ + 2066306122745343237483669467464293469194680096834470280624398144\ + 7140309400278171194198038370675489371535762220733644100930478390\ + 9871197489979144724073675307870340798761005614290980492634226688 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5B3%2C2239%5D + func test3RaisedToPrime333() { + NBKAssertExponentiation(T(3), Int(2239), T(""" + 0000000000000000000188143542653317364740047262022158266784428791\ + 9275755434856235633416147929751345775198585370887106410700145660\ + 6941136649945052148587729379215298759841906211465894489332805610\ + 3754563980603820020778896725273833377637201111950279005112886290\ + 8217517791462710719585984177457155945873475389047023763181890095\ + 9473781620831209436384360444149350498181207507201081140457731667\ + 8330429216786541702964381293439187677376199748692174845775469107\ + 1970497833817135114559784314771606933781164789651479259636951051\ + 1939631603190331045111418380453489110302905083967247056298476321\ + 3031701771676257422898074561340984020468039563665625492587401150\ + 2217805773793168451721091497379753074682133867791141932470210853\ + 5500447924439317916852983725285062418604919143133304424502097997\ + 8608095945569404820035699584592750436592636252055799816797294408\ + 0379347764424614210540528598264992483071934555760511919452459358\ + 8835641810301075822245153655314705395817134933252061409024669198\ + 8059476349693766699090206318226803178343171280950787682695695659\ + 6036250169540192297202679456092601217013126286587177412655204267 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5B5%2C4019%5D + func test5RaisedToPrime555() { + NBKAssertExponentiation(T(5), Int(4019), T(""" + 0000001446929684346652712293854771363608770525967600083755404601\ + 4957345870087500503487603669487412790514866287646265322998165123\ + 7858490002304274433672147699570659505153044896486895393750640165\ + 6928775867908279515437398191176238951828408573790734470345477155\ + 5523461654011508905437448709888495365320237507108067589052329024\ + 9150152007784011211339914449754828962361147846093684594339840255\ + 4082090351870280593564461792533581515740009197746416184126376462\ + 7513171712952497141572865808593203385483317716323751288867193425\ + 4148468649640058864230675104524048186517447302082906408424956362\ + 9758837840131897008299169989849297847761856730804217735049415782\ + 9576164079541459773697263304564453838344036135321806166247311605\ + 1583922759481958404593247769652134498168235251891967609838551519\ + 6895367299027108368711330107798776358904935596791346512797789271\ + 4896792453973244271314471709632569444905582089098918351559580722\ + 6321106414034452179867244499118249751063342223759587453914686539\ + 6908111618174630570000311233662035613887919737154518565754904733\ + 3083185530695058035521254105752988609692725798470777630752530204\ + 2599940027007370568347125202050752868479632687293640809602767930\ + 3858816432201682904268147124008525621379120457219167772120301585\ + 5924566379439864166360938720555906940258344296315856834431713110\ + 9031510071399560194606949946938965200495181099854874459742836621\ + 9452749381231066739863712410355985286770760288114233351958522528\ + 9254720092509662470547270010401979793646249028556880781998508960\ + 1361859999448519399006853526587504480164807765094325996443657804\ + 1840647438579682202685556945086347285534115616913220314483186795\ + 9505824453508868809675232062282535499100880724452941629449074254\ + 8612182352672327327268400829255931466201932710759855981331047638\ + 0373952548092040726975994716532293619257385003476756537912583205\ + 3118439654075379854319335205290809944413949455014265873545253078\ + 8330205282519080028427767192749459753122069080264973087241014307\ + 2832496925258959405329022843928903214208568103866527037140713169\ + 3604782550976252551168862593185575739685113169373933605227835303\ + 0847072871335150103185467131343559638580148070154916235638591521\ + 7551475263551504418572891033712157135476213809318196160948711372\ + 5354715015499902615236138501149706494374571817673933121619689549\ + 1190330835852177242160254166743595083040762847408006715353013832\ + 8458452645210177792497777945236485562922497538842118636928202205\ + 3232781215026991677078777075079415868972420095294308064034517889\ + 5294513805950305684358059918968985264729204194891997038141044289\ + 4523351216180823177725756322850045350978670133665384205423770116\ + 2034072860275538780053702353667090377996048746658421230595438359\ + 4351041626743397066325398137462696656196425405090145037319940783\ + 4075423829513127773206584989704512568918200936953799420923277344\ + 2116738501755407694565787324325611962194670923054218292236328125 + """)) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5B7%2C5903%5D + func test7RaisedToPrime777() { + NBKAssertExponentiation(T(7), Int(5903), T(""" + 0004108943827532289998252241834161383961424609336721429562672973\ + 5215518660156770969551613947438106226819575618431824632656548784\ + 2443630744318409823032653940945721503598477652901203967391204332\ + 3158222996451925544379097239021867537542941225033407598605764422\ + 5626993205372457839766802826979647293572000260187726319652445485\ + 9482777216365497907324653716024518534469506020670363036282940141\ + 7345349149930883359235820343903927339761930696186308207677700409\ + 7391771164922837159313352006942436230958342761245333909697097098\ + 1962850117306746317942719737152987263783869529445450162201013093\ + 7640979740872661278132106700453973743232978892847809183649542178\ + 6386091024874014251100007758237318828196343521562370522840436333\ + 9860937826427665567828847794223264241229145944928596285455954773\ + 2336371045463929134249803534108451709651747011690640152682259071\ + 7588531222847352542685069886646970884179932109354875736278011717\ + 7049137345311907474904031124084012054229020837573682684449616986\ + 1141963222206845750828398145035163722273565209503954216564277782\ + 9345151605641026739460433186606694775097789988243538915830478736\ + 2321105525900626126720677155472003434944779964774589232951904517\ + 9476680111837682980783634668338283785251186754580916022872774476\ + 8248487173769642087282206643072554696940829885901306725576309209\ + 1743074872375459772452624462584335614850487024186238154804049698\ + 4811375470004856107048221190933505123463191157187870352180325359\ + 3741701718672664302615728918968015750489563267192890269446915173\ + 1701093323994084381646062513005671630985001682866606254371387996\ + 8024992986421373100014171354432561066598242954612339431648999137\ + 9051435679527308334014939171040310771958013669805318524543112813\ + 9957017193329249909184553798390058883185333407503584493257244158\ + 3266967356357550201757284978687473572038818544870024112088525474\ + 8571207645144242434181117672975231370371178492357391865766085377\ + 3823840040081314628441473981477003917858676159209438834345026935\ + 4779790020210041341578847715514924396711295298299953107848651502\ + 3769622943601147847225941911366166628697715831218025798784981651\ + 6594489454864735330027409414601808651740177800327884257547084972\ + 2974937680043549927608417044479914400414576182906969146216064813\ + 9797351302752302750367394658157006251127397997773654189941600295\ + 7012943921820728784912336613928263599040635592438852410591446463\ + 2206241342371241353735828614033633079948725931648022365152412010\ + 6536877818941494267763684966615953104317136956765112250407063913\ + 3623022142786314689201462019186500031543501414431154405127756671\ + 2598842710382317599518208183440935184711587670120132882808742348\ + 8411078298769546381717505913293931478168035555632794459447381827\ + 1468641906416458172696166794340888092638284873221835454582235513\ + 3898834466941889918244651488283379527147807349915745308667074963\ + 7891453340202992598013755301769390340910183288640813995555377044\ + 7223588515487024291479342125463949093313578539672841465173598174\ + 6497929985814101267907129298071776716937287674794676561056646943\ + 0732206345508882216332886917818007802132509658343825952463482298\ + 4489495136960700641892386060280455771911594308242281539457704395\ + 9524507677196150124432182309556548761806281803523338664967704979\ + 3460861648738117020310880747550817881593881271702214461077779340\ + 4287970525724476964313573471187561031001209171965777853627292097\ + 8752509881640464168980655122431992653071443051558073785207534985\ + 4321311390667792122896825769874659348335793677512574761787460891\ + 0940419324785857595375679045664913268485224001615591380491428459\ + 9770610934799452407468859548167516086051739430826568377985552353\ + 5827900814770399339897945479367857446392755360019877423764266384\ + 9102974526553855472041319878092661554915548899695716722333975665\ + 7217654413703071682361274283821111835404123486866747021789194573\ + 4534154982476166843306613439440924368550646996797997564717871253\ + 9160649498393301802347586561673042384642389863462685684046394436\ + 5346633812583044014990173666027640872684548673874459368061904085\ + 1833388235372538302693052181739532042295454028340795279479946777\ + 0998436672566006010388682401863627158348794580771807628351724156\ + 9645262878014094496495419172431359232834857581736063818066222047\ + 8022377634336210803408343245633680822509378298099363690965609414\ + 4196836682956302330613169375496300657119374497326438865815833130\ + 6641482714265346330788386216670657593653569569417576198111004914\ + 1723667248154259119306662997353637860619174485149827167090042710\ + 6471414747419591688508026916865700879769503331013550956729099212\ + 7820605036546582266249968312554384036359924591010229549799331443\ + 1457638460474955690746307230167670856667830295141891662843469167\ + 0424763717677877513125882858810853633770618510938341766796723021\ + 6826062464545717657085175787821109704957381106356345712265138323\ + 0768347083961948674167484046428595865648150013889410250736872615\ + 6529299656645514273099767510443083082596626167467582361833369755\ + 6481100284602082844869451125548691905562882873118646312028536971\ + 1732106406529921113787189197150818833289607479384389566344975672\ + 7365338338792781072340541456248573682006539809213546535950220343 + """)) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Exponentiation x UIntXL x Powers Of 10 +//*============================================================================* + +final class NBKFlexibleWidthTestsOnExponentiationByPowersOf10AsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: State + //=------------------------------------------------------------------------= + + static let x10000 = T("1\(String(repeating: "0", count: 10000))")! + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5BPower%5B10%2C1%5D%2C10000%5D + func testPower1RaisedTo10000() { + NBKAssertExponentiation(T("1\(String(repeating: "0", count: 1))")!, Int(10000), Self.x10000) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5BPower%5B10%2C10%5D%2C1000%5D + func testPower10RaisedTo1000() { + NBKAssertExponentiation(T("1\(String(repeating: "0", count: 10))")!, Int(1000), Self.x10000) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5BPower%5B10%2C100%5D%2C100%5D + func testPower100RaisedTo100() { + NBKAssertExponentiation(T("1\(String(repeating: "0", count: 100))")!, Int(100), Self.x10000) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5BPower%5B10%2C1000%5D%2C10%5D + func testPower1000RaisedTo10() { + NBKAssertExponentiation(T("1\(String(repeating: "0", count: 1000))")!, Int(10), Self.x10000) + } + + /// https://www.wolframalpha.com/input?i2d=true&i=Power%5BPower%5B10%2C10000%5D%2C1%5D + func testPower10000RaisedTo1() { + NBKAssertExponentiation(Self.x10000, Int(1), Self.x10000) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Exponentiation x Assertions +//*============================================================================* + +private func NBKAssertExponentiation( +_ base: T, _ exponent: Int, _ power: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + XCTAssertEqual(base.power(exponent), power, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Literals.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Literals.swift new file mode 100644 index 00000000..ed6065c4 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Literals.swift @@ -0,0 +1,103 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Literals x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnLiteralsAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testFromIntegerLiteral() { + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), (0)) + XCTAssertEqual(T(x64:[ 10, 0, 0, 0] as X64), (10)) + XCTAssertEqual(T(x64:[ 2, 0, 0, 0] as X64), (0b10)) + XCTAssertEqual(T(x64:[ 8, 0, 0, 0] as X64), (0o10)) + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), (0x10)) + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), (0x10)) + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), (+0)) + XCTAssertEqual(T(x64:[ 10, 0, 0, 0] as X64), (+10)) + XCTAssertEqual(T(x64:[ 2, 0, 0, 0] as X64), (+0b10)) + XCTAssertEqual(T(x64:[ 8, 0, 0, 0] as X64), (+0o10)) + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), (+0x10)) + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), (+0x10)) + #if SBI && swift(>=5.8) + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), (0x000000000000000000000000000000000000000000000000000000000000000000000000000000)) + XCTAssertEqual(T(x64:[ ~0, 0, 0, 0] as X64), (0x00000000000000000000000000000000000000000000000000000000000000ffffffffffffffff)) + XCTAssertEqual(T(x64:[ ~0, ~0, 0, 0] as X64), (0x0000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff)) + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, 0] as X64), (0x000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff)) + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, ~0] as X64), (0x00000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff)) + XCTAssertEqual(T(x64:[ 0, ~0, ~0, ~0] as X64), (0x00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000)) + XCTAssertEqual(T(x64:[ 0, 0, ~0, ~0] as X64), (0x00000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000)) + XCTAssertEqual(T(x64:[ 0, 0, 0, ~0] as X64), (0x00000000000000ffffffffffffffff000000000000000000000000000000000000000000000000)) + XCTAssertEqual(T(exactlyIntegerLiteral: (-0x000000000000000000000000000000000000000000000000000000000000000000000000000001)), nil) + + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), (00000000000000000000000000000000000000000000000000000000000000000000000000000000)) + XCTAssertEqual(T(x64:[ ~0, 0, 0, 0] as X64), (00000000000000000000000000000000000000000000000000000000000018446744073709551615)) + XCTAssertEqual(T(x64:[ ~0, ~0, 0, 0] as X64), (00000000000000000000000000000000000000000340282366920938463463374607431768211455)) + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, 0] as X64), (00000000000000000000006277101735386680763835789423207666416102355444464034512895)) + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, ~0] as X64), (00115792089237316195423570985008687907853269984665640564039457584007913129639935)) + XCTAssertEqual(T(x64:[ 0, ~0, ~0, ~0] as X64), (00115792089237316195423570985008687907853269984665640564039439137263839420088320)) + XCTAssertEqual(T(x64:[ 0, 0, ~0, ~0] as X64), (00115792089237316195423570985008687907852929702298719625575994209400481361428480)) + XCTAssertEqual(T(x64:[ 0, 0, 0, ~0] as X64), (00115792089237316195417293883273301227089434195242432897623355228563449095127040)) + XCTAssertEqual(T(exactlyIntegerLiteral: (-00000000000000000000000000000000000000000000000000000000000000000000000000000001)), nil) + #else + XCTAssertEqual(T(integerLiteral: UInt.max), T(x64:[UInt64(UInt.max), 0, 0, 0] as X64)) + XCTAssertEqual(T(integerLiteral: UInt.min), T(x64:[UInt64(UInt.min), 0, 0, 0] as X64)) + #endif + } + + func testFromStringLiteral() { + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), "0") + XCTAssertEqual(T(x64:[ 10, 0, 0, 0] as X64), "10") + XCTAssertEqual(T(x64:[ 2, 0, 0, 0] as X64), "0b10") + XCTAssertEqual(T(x64:[ 8, 0, 0, 0] as X64), "0o10") + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), "0x10") + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), "0x10") + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), "+0") + XCTAssertEqual(T(x64:[ 10, 0, 0, 0] as X64), "+10") + XCTAssertEqual(T(x64:[ 2, 0, 0, 0] as X64), "+0b10") + XCTAssertEqual(T(x64:[ 8, 0, 0, 0] as X64), "+0o10") + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), "+0x10") + XCTAssertEqual(T(x64:[ 16, 0, 0, 0] as X64), "+0x10") + + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), "0x000000000000000000000000000000000000000000000000000000000000000000000000000000") + XCTAssertEqual(T(x64:[ ~0, 0, 0, 0] as X64), "0x00000000000000000000000000000000000000000000000000000000000000ffffffffffffffff") + XCTAssertEqual(T(x64:[ ~0, ~0, 0, 0] as X64), "0x0000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff") + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, 0] as X64), "0x000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff") + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, ~0] as X64), "0x00000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") + XCTAssertEqual(T(x64:[ 0, ~0, ~0, ~0] as X64), "0x00000000000000ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000") + XCTAssertEqual(T(x64:[ 0, 0, ~0, ~0] as X64), "0x00000000000000ffffffffffffffffffffffffffffffff00000000000000000000000000000000") + XCTAssertEqual(T(x64:[ 0, 0, 0, ~0] as X64), "0x00000000000000ffffffffffffffff000000000000000000000000000000000000000000000000") + XCTAssertEqual(T(exactlyStringLiteral: "-0x000000000000000000000000000000000000000000000000000000000000000000000000000001"), nil) + + XCTAssertEqual(T(x64:[ 0, 0, 0, 0] as X64), "00000000000000000000000000000000000000000000000000000000000000000000000000000000") + XCTAssertEqual(T(x64:[ ~0, 0, 0, 0] as X64), "00000000000000000000000000000000000000000000000000000000000018446744073709551615") + XCTAssertEqual(T(x64:[ ~0, ~0, 0, 0] as X64), "00000000000000000000000000000000000000000340282366920938463463374607431768211455") + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, 0] as X64), "00000000000000000000006277101735386680763835789423207666416102355444464034512895") + XCTAssertEqual(T(x64:[ ~0, ~0, ~0, ~0] as X64), "00115792089237316195423570985008687907853269984665640564039457584007913129639935") + XCTAssertEqual(T(x64:[ 0, ~0, ~0, ~0] as X64), "00115792089237316195423570985008687907853269984665640564039439137263839420088320") + XCTAssertEqual(T(x64:[ 0, 0, ~0, ~0] as X64), "00115792089237316195423570985008687907852929702298719625575994209400481361428480") + XCTAssertEqual(T(x64:[ 0, 0, 0, ~0] as X64), "00115792089237316195417293883273301227089434195242432897623355228563449095127040") + XCTAssertEqual(T(exactlyStringLiteral: "-00000000000000000000000000000000000000000000000000000000000000000000000000000001"), nil) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Logic.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Logic.swift new file mode 100644 index 00000000..7d1915bb --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Logic.swift @@ -0,0 +1,112 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Logic x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnLogicAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testNot() { + NBKAssertNot(T(words:[ 0, 0, 0, 0] as X), T(words:[~0, 0, 0, 0] as X)) + NBKAssertNot(T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 0, 0, 0, 0] as X)) + + NBKAssertNot(T(words:[ 0, 1, 2, 3] as X), T(words:[~0, ~1, ~2, ~3] as X)) + NBKAssertNot(T(words:[~0, ~1, ~2, ~3] as X), T(words:[ 0, 1, 2, 3] as X)) + } + + func testAnd() { + NBKAssertAnd(T(words:[ 0, 1, 2, 3] as X), T(words:[ 0, 0, 0, 0] as X), T(words:[ 0, 0, 0, 0] as X)) + NBKAssertAnd(T(words:[ 3, 2, 1, 0] as X), T(words:[ 0, 0, 0, 0] as X), T(words:[ 0, 0, 0, 0] as X)) + + NBKAssertAnd(T(words:[ 0, 1, 2, 3] as X), T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 0, 1, 2, 3] as X)) + NBKAssertAnd(T(words:[ 3, 2, 1, 0] as X), T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 3, 2, 1, 0] as X)) + + NBKAssertAnd(T(words:[ 0, 1, 2, 3] as X), T(words:[ 1, 1, 1, 1] as X), T(words:[ 0, 1, 0, 1] as X)) + NBKAssertAnd(T(words:[ 3, 2, 1, 0] as X), T(words:[ 1, 1, 1, 1] as X), T(words:[ 1, 0, 1, 0] as X)) + } + + func testOr() { + NBKAssertOr (T(words:[ 0, 1, 2, 3] as X), T(words:[ 0, 0, 0, 0] as X), T(words:[ 0, 1, 2, 3] as X)) + NBKAssertOr (T(words:[ 3, 2, 1, 0] as X), T(words:[ 0, 0, 0, 0] as X), T(words:[ 3, 2, 1, 0] as X)) + + NBKAssertOr (T(words:[ 0, 1, 2, 3] as X), T(words:[~0, ~0, ~0, ~0] as X), T(words:[~0, ~0, ~0, ~0] as X)) + NBKAssertOr (T(words:[ 3, 2, 1, 0] as X), T(words:[~0, ~0, ~0, ~0] as X), T(words:[~0, ~0, ~0, ~0] as X)) + + NBKAssertOr (T(words:[ 0, 1, 2, 3] as X), T(words:[ 1, 1, 1, 1] as X), T(words:[ 1, 1, 3, 3] as X)) + NBKAssertOr (T(words:[ 3, 2, 1, 0] as X), T(words:[ 1, 1, 1, 1] as X), T(words:[ 3, 3, 1, 1] as X)) + } + + func testXor() { + NBKAssertXor(T(words:[ 0, 1, 2, 3] as X), T(words:[ 0, 0, 0, 0] as X), T(words:[ 0, 1, 2, 3] as X)) + NBKAssertXor(T(words:[ 3, 2, 1, 0] as X), T(words:[ 0, 0, 0, 0] as X), T(words:[ 3, 2, 1, 0] as X)) + + NBKAssertXor(T(words:[ 0, 1, 2, 3] as X), T(words:[~0, ~0, ~0, ~0] as X), T(words:[~0, ~1, ~2, ~3] as X)) + NBKAssertXor(T(words:[ 3, 2, 1, 0] as X), T(words:[~0, ~0, ~0, ~0] as X), T(words:[~3, ~2, ~1, ~0] as X)) + + NBKAssertXor(T(words:[ 0, 1, 2, 3] as X), T(words:[ 1, 1, 1, 1] as X), T(words:[ 1, 0, 3, 2] as X)) + NBKAssertXor(T(words:[ 3, 2, 1, 0] as X), T(words:[ 1, 1, 1, 1] as X), T(words:[ 2, 3, 0, 1] as X)) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Logic x Assertions +//*============================================================================* + +private func NBKAssertNot( +_ operand: T, _ result: T, +file: StaticString = #file, line: UInt = #line) { + if operand.words.last != UInt.max { + XCTAssertEqual(~operand, result, file: file, line: line) + XCTAssertEqual(~result, operand, file: file, line: line) + } else { + XCTAssertEqual(~operand, result, file: file, line: line) + } +} + +private func NBKAssertAnd( +_ lhs: T, _ rhs: T, _ result: T, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual( lhs & rhs, result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs &= rhs; return lhs }(), result, file: file, line: line) + XCTAssertEqual( rhs & lhs, result, file: file, line: line) + XCTAssertEqual({ var rhs = rhs; rhs &= lhs; return rhs }(), result, file: file, line: line) +} + +private func NBKAssertOr( +_ lhs: T, _ rhs: T, _ result: T, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual( lhs | rhs, result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs |= rhs; return lhs }(), result, file: file, line: line) + XCTAssertEqual( rhs | lhs, result, file: file, line: line) + XCTAssertEqual({ var rhs = rhs; rhs |= lhs; return rhs }(), result, file: file, line: line) +} + +private func NBKAssertXor( +_ lhs: T, _ rhs: T, _ result: T, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual( lhs ^ rhs, result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs ^= rhs; return lhs }(), result, file: file, line: line) + XCTAssertEqual( rhs ^ lhs, result, file: file, line: line) + XCTAssertEqual({ var rhs = rhs; rhs ^= lhs; return rhs }(), result, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Multiplication.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Multiplication.swift new file mode 100644 index 00000000..c03ef702 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Multiplication.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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Multiplication x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnMultiplicationAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testMultiplying() { + NBKAssertMultiplication(T(words:[ 1, 2, 3, 4] as X), T(words:[2, 0, 0, 0] as X), T(words:[ 2, 4, 6, 8, 0, 0, 0, 0] as X)) + NBKAssertMultiplication(T(words:[ 1, 2, 3, 4] as X), T(words:[0, 2, 0, 0] as X), T(words:[ 0, 2, 4, 6, 8, 0, 0, 0] as X)) + NBKAssertMultiplication(T(words:[ 1, 2, 3, 4] as X), T(words:[0, 0, 2, 0] as X), T(words:[ 0, 0, 2, 4, 6, 8, 0, 0] as X)) + NBKAssertMultiplication(T(words:[ 1, 2, 3, 4] as X), T(words:[0, 0, 0, 2] as X), T(words:[ 0, 0, 0, 2, 4, 6, 8, 0] as X)) + + NBKAssertMultiplication(T(words:[~1, ~2, ~3, ~4] as X), T(words:[2, 0, 0, 0] as X), T(words:[~3, ~4, ~6, ~8, 1, 0, 0, 0] as X)) + NBKAssertMultiplication(T(words:[~1, ~2, ~3, ~4] as X), T(words:[0, 2, 0, 0] as X), T(words:[ 0, ~3, ~4, ~6, ~8, 1, 0, 0] as X)) + NBKAssertMultiplication(T(words:[~1, ~2, ~3, ~4] as X), T(words:[0, 0, 2, 0] as X), T(words:[ 0, 0, ~3, ~4, ~6, ~8, 1, 0] as X)) + NBKAssertMultiplication(T(words:[~1, ~2, ~3, ~4] as X), T(words:[0, 0, 0, 2] as X), T(words:[ 0, 0, 0, ~3, ~4, ~6, ~8, 1] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit (and Self) + //=------------------------------------------------------------------------= + + func testMultiplyingByDigit() { + NBKAssertMultiplicationByDigit(T(words:[1, 2, 3, 4] as X), UInt(0), T(words:[ 0, 0, 0, 0, 0] as X)) + NBKAssertMultiplicationByDigit(T(words:[1, 2, 3, 4] as X), UInt(1), T(words:[ 1, 2, 3, 4, 0] as X)) + NBKAssertMultiplicationByDigit(T(words:[1, 2, 3, 4] as X), UInt(2), T(words:[ 2, 4, 6, 8, 0] as X)) + + NBKAssertMultiplicationByDigit(T(words:[1, 2, 3, 4] as X), ~UInt(0), ~T(words:[ 0, 1, 1, 1, ~3] as X)) + NBKAssertMultiplicationByDigit(T(words:[1, 2, 3, 4] as X), ~UInt(1), ~T(words:[ 1, 3, 4, 5, ~3] as X)) + NBKAssertMultiplicationByDigit(T(words:[1, 2, 3, 4] as X), ~UInt(2), ~T(words:[ 2, 5, 7, 9, ~3] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit x Addition + //=------------------------------------------------------------------------= + + func testMultiplyingByDigitWithAddition() { + NBKAssertMultiplicationByDigitWithAddition(T(words:[~0, ~0, ~0, ~0] as X), 0, 0, T(words:[ 0, 0, 0, 0, 0] as X)) + NBKAssertMultiplicationByDigitWithAddition(T(words:[~0, ~0, ~0, ~0] as X), 0, ~0, T(words:[~0, 0, 0, 0, 0] as X)) + NBKAssertMultiplicationByDigitWithAddition(T(words:[~0, ~0, ~0, ~0] as X), ~0, 0, T(words:[ 1, ~0, ~0, ~0, ~1] as X)) + NBKAssertMultiplicationByDigitWithAddition(T(words:[~0, ~0, ~0, ~0] as X), ~0, ~0, T(words:[ 0, 0, 0, 0, ~0] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Square + //=------------------------------------------------------------------------= + + func testMultiplyingBySquaring() { + NBKAssertMultiplicationBySquaring(T(words:[ 0, 0, 0, 0] as X), T(words:[ 0, 0, 0, 0, 0, 0, 0, 0] as X)) + NBKAssertMultiplicationBySquaring(T(words:[ 1, 2, 3, 4] as X), T(words:[ 1, 4, 10, 20, 25, 24, 16, 0] as X)) + NBKAssertMultiplicationBySquaring(T(words:[~1, ~2, ~3, ~4] as X), T(words:[ 4, 8, 16, 28, 21, 20, 10, ~7] as X)) + NBKAssertMultiplicationBySquaring(T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 1, 0, 0, 0, ~1, ~0, ~0, ~0] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x *= 0) + XCTAssertNotNil(x.multiply(by: 0, add: 0)) + + XCTAssertNotNil(x * 0) + XCTAssertNotNil(x.multiplied(by: 0, adding: 0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Multiplication x Assertions +//*============================================================================* + +private func NBKAssertMultiplication( +_ lhs: T, _ rhs: T, _ product: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + XCTAssertEqual( lhs * rhs, product, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs *= rhs; return lhs }(), product, file: file, line: line) +} + +private func NBKAssertMultiplicationByDigit( +_ lhs: T, _ rhs: T.Digit, _ product: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + NBKAssertMultiplication(lhs, T(digit: rhs), product, file: file, line: line) + //=------------------------------------------= + XCTAssertEqual( lhs * rhs, product, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs *= rhs; return lhs }(), product, file: file, line: line) +} + +private func NBKAssertMultiplicationBySquaring( +_ base: T, _ product: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + NBKAssertMultiplication(base, base, product, file: file, line: line) + //=------------------------------------------= + XCTAssertEqual( base.squared(), product, file: file, line: line) + XCTAssertEqual({ var base = base; base.square (); return base }(), product, file: file, line: line) +} + +//=----------------------------------------------------------------------------= +// MARK: + UIntXL +//=----------------------------------------------------------------------------= + +private func NBKAssertMultiplicationByDigitWithAddition( +_ lhs: UIntXL, _ rhs: UInt, _ addend: UInt, _ product: UIntXL, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + XCTAssertEqual(lhs.multiplied(by: rhs, adding: addend), product, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.multiply(by: rhs, add: addend); return lhs }(), product, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Numbers.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Numbers.swift new file mode 100644 index 00000000..e7c20195 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Numbers.swift @@ -0,0 +1,345 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Numbers x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnNumbersAsUIntXL: XCTestCase { + + typealias S = IntXL + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testZero() { + XCTAssertEqual(T( 0), T(words:[0])) + XCTAssertEqual(T.zero, T(words:[0])) + + for x in T.basket { + XCTAssertEqual(x + T.zero, x) + XCTAssertEqual(T.zero + x, x) + + XCTAssertEqual(x - x, T.zero) + XCTAssertEqual(x - T.zero, x) + } + } + + func testOne() { + XCTAssertEqual(T( 1), T(words:[1])) + XCTAssertEqual(T.one, T(words:[1])) + + for x in T.basket { + XCTAssertEqual(x * T.one, x) + XCTAssertEqual(T.one * x, x) + + XCTAssertEqual(x / T.one, x) + XCTAssertEqual(x % T.one, T.zero) + + if !x.isZero { + XCTAssertEqual(x / x, T.one ) + XCTAssertEqual(x % x, T.zero) + } + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Int + //=------------------------------------------------------------------------= + + func testToInt() { + NBKAssertNumbers(from: T(words:[ 1, 0, 0, 0] as X), default: Int( 1)) + NBKAssertNumbers(from: T(words:[~0, 0, 0, 0] as X), exactly: nil, clamping: Int.max, truncating: -1) + NBKAssertNumbers(from: T(words:[ 1, 1, 1, 1] as X), exactly: nil, clamping: Int.max, truncating: 1) + NBKAssertNumbers(from: T(words:[~0, ~0, ~0, ~0] as X), exactly: nil, clamping: Int.max, truncating: -1) + } + + func testFromInt() { + NBKAssertNumbers(from: Int.min, exactly: nil, clamping: 0, truncating: T(words: Int.min.words)) + NBKAssertNumbers(from: Int.max, default: /*-------------------------*/ T(words: Int.max.words)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Int32 + //=------------------------------------------------------------------------= + + func testToInt32() { + NBKAssertNumbers(from: T(x32:[ 1, 0, 0, 0] as X32), default: Int32( 1)) + NBKAssertNumbers(from: T(x32:[~0, 0, 0, 0] as X32), exactly: nil, clamping: Int32.max, truncating: -1) + NBKAssertNumbers(from: T(x32:[ 1, 1, 1, 1] as X32), exactly: nil, clamping: Int32.max, truncating: 1) + NBKAssertNumbers(from: T(x32:[~0, ~0, ~0, ~0] as X32), exactly: nil, clamping: Int32.max, truncating: -1) + } + + func testFromInt32() { + NBKAssertNumbers(from: Int32.min, exactly: nil, clamping: 0, truncating: T(words: Int32.min.words)) + NBKAssertNumbers(from: Int32.max, default: /*-------------------------*/ T(words: Int32.max.words)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Int64 + //=------------------------------------------------------------------------= + + func testToInt64() { + NBKAssertNumbers(from: T(x64:[ 1, 0, 0, 0] as X64), default: Int64( 1)) + NBKAssertNumbers(from: T(x64:[~0, 0, 0, 0] as X64), exactly: nil, clamping: Int64.max, truncating: -1) + NBKAssertNumbers(from: T(x64:[ 1, 1, 1, 1] as X64), exactly: nil, clamping: Int64.max, truncating: 1) + NBKAssertNumbers(from: T(x64:[~0, ~0, ~0, ~0] as X64), exactly: nil, clamping: Int64.max, truncating: -1) + } + + func testFromInt64() { + NBKAssertNumbers(from: Int64.min, exactly: nil, clamping: 0, truncating: T(words: Int64.min.words)) + NBKAssertNumbers(from: Int64.max, default: /*-------------------------*/ T(words: Int64.max.words)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x UInt + //=------------------------------------------------------------------------= + + func testToUInt() { + NBKAssertNumbers(from: T(words:[ 1, 0, 0, 0] as X), default: UInt( 1)) + NBKAssertNumbers(from: T(words:[~0, 0, 0, 0] as X), default: ~UInt( 0)) + NBKAssertNumbers(from: T(words:[ 1, 1, 1, 1] as X), exactly: nil, clamping: UInt.max, truncating: 1) + NBKAssertNumbers(from: T(words:[~0, ~0, ~0, ~0] as X), exactly: nil, clamping: UInt.max, truncating: ~0) + } + + func testFromUInt() { + NBKAssertNumbers(from: UInt.min, default: T(words: UInt.min.words)) + NBKAssertNumbers(from: UInt.max, default: T(words: UInt.max.words)) + } + + func testFromUIntAsDigit() { + NBKAssertNumbers(from: T(digit: UInt.min), default: T(words:[ 0, 0, 0, 0] as X)) + NBKAssertNumbers(from: T(digit: UInt.max), default: T(words:[~0, 0, 0, 0] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x UInt32 + //=------------------------------------------------------------------------= + + func testToUInt32() { + NBKAssertNumbers(from: T(x32:[ 1, 0, 0, 0] as X32), default: UInt32( 1)) + NBKAssertNumbers(from: T(x32:[~0, 0, 0, 0] as X32), default: ~UInt32( 0)) + NBKAssertNumbers(from: T(x32:[ 1, 1, 1, 1] as X32), exactly: nil, clamping: UInt32.max, truncating: 1) + NBKAssertNumbers(from: T(x32:[~0, ~0, ~0, ~0] as X32), exactly: nil, clamping: UInt32.max, truncating: ~0) + } + + func testFromUInt32() { + NBKAssertNumbers(from: UInt32.min, default: T(words: UInt32.min.words)) + NBKAssertNumbers(from: UInt32.max, default: T(words: UInt32.max.words)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x UInt64 + //=------------------------------------------------------------------------= + + func testToUInt64() { + NBKAssertNumbers(from: T(x64:[ 1, 0, 0, 0] as X64), default: UInt64( 1)) + NBKAssertNumbers(from: T(x64:[~0, 0, 0, 0] as X64), default: ~UInt64( 0)) + NBKAssertNumbers(from: T(x64:[ 1, 1, 1, 1] as X64), exactly: nil, clamping: UInt64.max, truncating: 1) + NBKAssertNumbers(from: T(x64:[~0, ~0, ~0, ~0] as X64), exactly: nil, clamping: UInt64.max, truncating: ~0) + } + + func testFromUInt64() { + NBKAssertNumbers(from: UInt64.min, default: T(words: UInt64.min.words)) + NBKAssertNumbers(from: UInt64.max, default: T(words: UInt64.max.words)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Magnitude + //=------------------------------------------------------------------------= + + func testToMagnitude() { + NBKAssertNumbers(from: T(words:[ 1, 0, 0, 0] as X), default: M(words:[ 1, 0, 0, 0] as X)) + NBKAssertNumbers(from: T(words:[~0, 0, 0, 0] as X), default: M(words:[~0, 0, 0, 0] as X)) + NBKAssertNumbers(from: T(words:[ 1, 1, 1, 1] as X), default: M(words:[ 1, 1, 1, 1] as X)) + NBKAssertNumbers(from: T(words:[~0, ~0, ~0, ~0] as X), default: M(words:[~0, ~0, ~0, ~0] as X)) + } + + func testFromMagnitude() { + NBKAssertNumbers(from: M(words:[ 1, 0, 0, 0] as X), default: T(words:[ 1, 0, 0, 0] as X)) + NBKAssertNumbers(from: M(words:[~0, 0, 0, 0] as X), default: T(words:[~0, 0, 0, 0] as X)) + NBKAssertNumbers(from: M(words:[ 1, 1, 1, 1] as X), default: T(words:[ 1, 1, 1, 1] as X)) + NBKAssertNumbers(from: M(words:[~0, ~0, ~0, ~0] as X), default: T(words:[~0, ~0, ~0, ~0] as X)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Float32 + //=------------------------------------------------------------------------= + + func testToFloat32() { + XCTAssertEqual(Float32(T(0)), Float32(0)) + XCTAssertEqual(Float32(T(1)), Float32(1)) + + XCTAssertEqual(Float32(T(UInt32.min)), Float32(UInt32.min)) + XCTAssertEqual(Float32(T(UInt32.max)), Float32(UInt32.max)) + } + + func testFromFloat32() { + XCTAssertEqual(T(Float32( 22.0)), 22) + XCTAssertEqual(T(Float32( 22.5)), 22) + + XCTAssertEqual(T(exactly: 22.5), nil) + XCTAssertEqual(T(exactly: -22.5), nil) + + XCTAssertEqual(T(exactly: pow(2, Float32(64 * 0 - 1))), nil) + XCTAssertEqual(T(exactly: pow(2, Float32(64 * 0 - 0))), T(x64:[1, 0, 0, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float32(64 * 1 - 1))), T(x64:[1 << 63, 0, 0, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float32(64 * 2 - 1))), T(x64:[0, 1 << 63, 0, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float32(64 * 2 - 0))), nil) + } + + func testFromFloat32ValuesThatAreSpecial() { + XCTAssertNil(T(exactly: Float32.nan)) + XCTAssertNil(T(exactly: Float32.infinity)) + XCTAssertNil(T(exactly: Float32.signalingNaN)) + XCTAssertNil(T(exactly: Float32.leastNormalMagnitude)) + XCTAssertNil(T(exactly: Float32.leastNonzeroMagnitude)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Float64 + //=------------------------------------------------------------------------= + + func testToFloat64() { + XCTAssertEqual(Float64(T(0)), Float64(0)) + XCTAssertEqual(Float64(T(1)), Float64(1)) + + XCTAssertEqual(Float64(T(UInt64.min)), Float64(UInt64.min)) + XCTAssertEqual(Float64(T(UInt64.max)), Float64(UInt64.max)) + } + + func testFromFloat64() { + XCTAssertEqual(T(Float64( 22.0)), 22) + XCTAssertEqual(T(Float64( 22.5)), 22) + + XCTAssertEqual(T(exactly: 22.5), nil) + XCTAssertEqual(T(exactly: -22.5), nil) + + XCTAssertEqual(T(exactly: pow(2, Float64(64 * 0 - 1))), nil) + XCTAssertEqual(T(exactly: pow(2, Float64(64 * 0 - 0))), T(x64:[1, 0, 0, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float64(64 * 1 - 1))), T(x64:[1 << 63, 0, 0, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float64(64 * 2 - 1))), T(x64:[0, 1 << 63, 0, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float64(64 * 3 - 1))), T(x64:[0, 0, 1 << 63, 0] as X64)) + XCTAssertEqual(T(exactly: pow(2, Float64(64 * 4 - 1))), T(x64:[0, 0, 0, 1 << 63] as X64)) + } + + func testFromFloat64ValuesThatAreSpecial() { + XCTAssertNil(T(exactly: Float64.nan)) + XCTAssertNil(T(exactly: Float64.infinity)) + XCTAssertNil(T(exactly: Float64.signalingNaN)) + XCTAssertNil(T(exactly: Float64.leastNormalMagnitude)) + XCTAssertNil(T(exactly: Float64.leastNonzeroMagnitude)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Sign & Magnitude + //=------------------------------------------------------------------------= + + func testsFromSignAndMagnitude() { + XCTAssertEqual(T(sign: .plus, magnitude: M( 1)), T( 1)) + XCTAssertEqual(T(sign: .minus, magnitude: M( 1)), nil) + } + + func testsFromSignAndMagnitudeAsPlusMinusZero() { + XCTAssertEqual(T(sign: .plus, magnitude: M( )), T( )) + XCTAssertEqual(T(sign: .minus, magnitude: M( )), T( )) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Numbers x Open Source Issues +//*============================================================================* + +final class NBKFlexibleWidthTestsOnNumbersOpenSourceIssues: XCTestCase { + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + /// https://github.com/apple/swift-numerics/pull/254 + /// + /// - Note: Said to crash and return incorrect values. + /// + func testSwiftNumericsPull254() { + XCTAssertEqual(UInt64( UIntXL(UInt64.max)), UInt64(UInt64.max)) + XCTAssertEqual(UIntXL( UInt64(UInt64.max)), UIntXL(UInt64.max)) + + XCTAssertEqual(UInt64(exactly: UIntXL(UInt64.max)), UInt64(UInt64.max)) + XCTAssertEqual(UIntXL(exactly: UInt64(UInt64.max)), UIntXL(UInt64.max)) + + XCTAssertEqual(UInt64(clamping: UIntXL(UInt64.max)), UInt64(UInt64.max)) + XCTAssertEqual(UIntXL(clamping: UInt64(UInt64.max)), UIntXL(UInt64.max)) + } + + /// https://github.com/apple/swift-numerics/pull/258 + /// + /// - Note: Said to crash when using Float80 (can't test it). + /// + func testSwiftNumericsPull258() { + XCTAssertEqual( + Float32(exactly: UInt64(UInt64(1) << Float32.significandBitCount)), + Float32(exactly: UIntXL(UInt64(1) << Float32.significandBitCount))) + + XCTAssertEqual( + Float64(exactly: UInt64(UInt64(1) << Float64.significandBitCount)), + Float64(exactly: UIntXL(UInt64(1) << Float64.significandBitCount))) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Numbers x Assertions +//*============================================================================* + +private func NBKAssertNumbers( +from value: I, default: O, +file: StaticString = #file, line: UInt = #line) { + NBKAssertNumbers(from: value, exactly: `default`, clamping: `default`, truncating: `default`, file: file, line: line) +} + +private func NBKAssertNumbers( +from value: I, default: O, exactly: O?, +file: StaticString = #file, line: UInt = #line) { + NBKAssertNumbers(from: value, exactly: exactly, clamping: `default`, truncating: `default`, file: file, line: line) +} + +private func NBKAssertNumbers( +from value: I, default: O, clamping: O, +file: StaticString = #file, line: UInt = #line) { + NBKAssertNumbers(from: value, exactly: `default`, clamping: clamping, truncating: `default`, file: file, line: line) +} + +private func NBKAssertNumbers( +from value: I, default: O, truncating: O, +file: StaticString = #file, line: UInt = #line) { + NBKAssertNumbers(from: value, exactly: `default`, clamping: `default`, truncating: truncating, file: file, line: line) +} + +private func NBKAssertNumbers( +from value: I, exactly: O?, clamping: O, truncating: O, +file: StaticString = #file, line: UInt = #line) { + //=--------------------------------------= + if let exactly = exactly { + XCTAssertEqual(O(value), exactly, file: file, line: line) + } + //=--------------------------------------= + XCTAssertEqual(O(exactly: value), exactly, file: file, line: line) + XCTAssertEqual(O(clamping: value), clamping, file: file, line: line) + XCTAssertEqual(O(truncatingIfNeeded: value), truncating, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Shifts.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Shifts.swift new file mode 100644 index 00000000..253495b6 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Shifts.swift @@ -0,0 +1,211 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Shifts x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnShiftsAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests x Left + //=------------------------------------------------------------------------= + + func testBitShiftingLeftByBits() { + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 0, T(x64:[ 1, 2, 3, 4] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 1, T(x64:[ 2, 4, 6, 8] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 2, T(x64:[ 4, 8, 12, 16] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 3, T(x64:[ 8, 16, 24, 32] as X64)) + } + + func testBitShiftingLeftByWords() { + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 0, T(x64:[ 1, 2, 3, 4, 0, 0, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 64, T(x64:[ 0, 1, 2, 3, 4, 0, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 128, T(x64:[ 0, 0, 1, 2, 3, 4, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 192, T(x64:[ 0, 0, 0, 1, 2, 3, 4, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 256, T(x64:[ 0, 0, 0, 0, 1, 2, 3, 4] as X64)) + } + + func testBitShiftingLeftByWordsAndBits() { + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 3, T(x64:[ 8, 16, 24, 32, 0, 0, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 67, T(x64:[ 0, 8, 16, 24, 32, 0, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 131, T(x64:[ 0, 0, 8, 16, 24, 32, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 195, T(x64:[ 0, 0, 0, 8, 16, 24, 32, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 1, 2, 3, 4] as X64), 259, T(x64:[ 0, 0, 0, 0, 8, 16, 24, 32] as X64)) + } + + func testBitShiftingLeftSuchThatWordsSplit() { + NBKAssertShiftLeft(T(x64:[~0, 0, 0, 0] as X64), 1, T(x64:[~1, 1, 0, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 0, ~0, 0, 0] as X64), 1, T(x64:[ 0, ~1, 1, 0, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 0, 0, ~0, 0] as X64), 1, T(x64:[ 0, 0, ~1, 1, 0] as X64)) + NBKAssertShiftLeft(T(x64:[ 0, 0, 0, ~0] as X64), 1, T(x64:[ 0, 0, 0, ~1, 1] as X64)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Right + //=------------------------------------------------------------------------= + + func testBitShiftingRightByBits() { + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 0, T(x64:[ 8, 16, 24, 32] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 1, T(x64:[ 4, 8, 12, 16] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 2, T(x64:[ 2, 4, 6, 8] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 3, T(x64:[ 1, 2, 3, 4] as X64)) + } + + func testBitShiftingRightByWords() { + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 0, T(x64:[ 8, 16, 24, 32] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 64, T(x64:[16, 24, 32, 0] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 128, T(x64:[24, 32, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 192, T(x64:[32, 0, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 256, T(x64:[ 0, 0, 0, 0] as X64)) + } + + func testBitShiftingRightByWordsAndBits() { + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 3, T(x64:[ 1, 2, 3, 4] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 67, T(x64:[ 2, 3, 4, 0] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 131, T(x64:[ 3, 4, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 195, T(x64:[ 4, 0, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[8, 16, 24, 32] as X64), 259, T(x64:[ 0, 0, 0, 0] as X64)) + } + + func testBitShiftingRightSuchThatWordsSplit() { + NBKAssertShiftRight(T(x64:[0, 0, 0, 7] as X64), 1, T(x64:[ 0, 0, 1 << 63, 3] as X64)) + NBKAssertShiftRight(T(x64:[0, 0, 7, 0] as X64), 1, T(x64:[ 0, 1 << 63, 3, 0] as X64)) + NBKAssertShiftRight(T(x64:[0, 7, 0, 0] as X64), 1, T(x64:[ 1 << 63, 3, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[7, 0, 0, 0] as X64), 1, T(x64:[ 3, 0, 0, 0] as X64)) + } + + func testBitShiftingRightIsUnsigned() { + NBKAssertShiftRight(T(x64:[0, 0, 0, 1 << 63] as X64), 0, T(x64:[0, 0, 0, 1 << 63] as X64)) + NBKAssertShiftRight(T(x64:[0, 0, 0, 1 << 63] as X64), 64, T(x64:[0, 0, 1 << 63, 0] as X64)) + NBKAssertShiftRight(T(x64:[0, 0, 0, 1 << 63] as X64), 128, T(x64:[0, 1 << 63, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[0, 0, 0, 1 << 63] as X64), 192, T(x64:[1 << 63, 0, 0, 0] as X64)) + NBKAssertShiftRight(T(x64:[0, 0, 0, 1 << 63] as X64), 256, T(x64:[0, 0, 0, 0] as X64)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testBitShiftingIsSmart() { + XCTAssertEqual(T(x64:[1, 2, 3, 4] as X64) << 1, T(x64:[2, 4, 6, 8, 0] as X64)) + XCTAssertEqual(T(x64:[1, 2, 3, 4] as X64) >> -1, T(x64:[2, 4, 6, 8, 0] as X64)) + + XCTAssertEqual(T(x64:[1, 2, 3, 4] as X64) << 64, T(x64:[0, 1, 2, 3, 4] as X64)) + XCTAssertEqual(T(x64:[1, 2, 3, 4] as X64) >> -64, T(x64:[0, 1, 2, 3, 4] as X64)) + } + + func testBitShiftingLeftByMoreThanBitWidthDoesNotTrap() { + NBKAssertShiftLeft (T(x64:[1] as X64), (UInt.bitWidth + 1), T(x64:[0, 2] as X64)) + NBKAssertShiftRight(T(x64:[1] as X64), -(UInt.bitWidth + 1), T(x64:[0, 2] as X64)) + } + + func testBitShiftingRightDoesNotTrap() { + XCTAssertEqual(T(x64:[1, 2, 3, 4] as X64) >> Int.max, T.zero) + XCTAssertEqual(T(x64:[1, 2, 3, 4] as X64) << Int.min, T.zero) + } + + func testBitShiftingZeroDoesNotTrap() { + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) << Int.min, T.zero) + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) << Int.max, T.zero) + + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) >> Int.min, T.zero) + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) >> Int.max, T.zero) + } + + func testBitShiftingZeroDoesNotDoAnything() { + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) << (UInt.bitWidth + 0), T.zero) + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) << (UInt.bitWidth + 1), T.zero) + + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) >> (UInt.bitWidth + 0), T.zero) + XCTAssertEqual(T(x64:[0, 0, 0, 0] as X64) >> (UInt.bitWidth + 1), T.zero) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Shifts x Assertions +//*============================================================================* + +private func NBKAssertShiftLeft( +_ lhs: T, _ rhs: Int, _ result: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + let (major, minor) = rhs.quotientAndRemainder(dividingBy: UInt.bitWidth) + //=------------------------------------------= + XCTAssertEqual( lhs << rhs, result, file: file, line: line) + XCTAssertEqual( lhs >> -rhs, result, file: file, line: line) + + XCTAssertEqual({ var lhs = lhs; lhs <<= rhs; return lhs }(), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs >>= -rhs; return lhs }(), result, file: file, line: line) + + XCTAssertEqual(lhs.bitShiftedLeftSmart(by: rhs), result, file: file, line: line) + XCTAssertEqual(lhs.bitShiftedRightSmart(by: -rhs), result, file: file, line: line) + + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftLeftSmart(by: rhs); return lhs }(), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftRightSmart(by: -rhs); return lhs }(), result, file: file, line: line) + //=------------------------------------------= + if major >= 0, minor >= 0 { + XCTAssertEqual(lhs.bitShiftedLeft(by: rhs), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftLeft(by: rhs); return lhs }(), result, file: file, line: line) + } + + if major >= 0, minor >= 0 { + XCTAssertEqual(lhs.bitShiftedLeft(major: major, minor: minor), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftLeft(major: major, minor: minor); return lhs }(), result, file: file, line: line) + } + + if major >= 0, minor == 0 { + XCTAssertEqual(lhs.bitShiftedLeft(major: major), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftLeft(major: major); return lhs }(), result, file: file, line: line) + } +} + +private func NBKAssertShiftRight( +_ lhs: T, _ rhs: Int, _ result: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + let (major, minor) = rhs.quotientAndRemainder(dividingBy: UInt.bitWidth) + //=------------------------------------------= + XCTAssertEqual( lhs >> rhs, result, file: file, line: line) + XCTAssertEqual( lhs << -rhs, result, file: file, line: line) + + XCTAssertEqual({ var lhs = lhs; lhs >>= rhs; return lhs }(), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs <<= -rhs; return lhs }(), result, file: file, line: line) + + XCTAssertEqual(lhs.bitShiftedRightSmart(by: rhs), result, file: file, line: line) + XCTAssertEqual(lhs.bitShiftedLeftSmart(by: -rhs), result, file: file, line: line) + + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftRightSmart(by: rhs); return lhs }(), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftLeftSmart(by: -rhs); return lhs }(), result, file: file, line: line) + //=------------------------------------------= + if major >= 0, minor >= 0 { + XCTAssertEqual(lhs.bitShiftedRight(by: rhs), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftRight(by: rhs); return lhs }(), result, file: file, line: line) + } + + if major >= 0, minor >= 0 { + XCTAssertEqual(lhs.bitShiftedRight(major: major, minor: minor), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftRight(major: major, minor: minor); return lhs }(), result, file: file, line: line) + } + + if major >= 0, minor == 0 { + XCTAssertEqual(lhs.bitShiftedRight(major: major), result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.bitShiftRight(major: major); return lhs }(), result, file: file, line: line) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Subtraction.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Subtraction.swift new file mode 100644 index 00000000..8fecfcf3 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Subtraction.swift @@ -0,0 +1,180 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Subtraction x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnSubtractionAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testSubtracting() { + NBKAssertSubtraction(T(3), T(0), Int(0), T(3)) + NBKAssertSubtraction(T(3), T(1), Int(0), T(2)) + NBKAssertSubtraction(T(3), T(2), Int(0), T(1)) + NBKAssertSubtraction(T(3), T(3), Int(0), T(0)) + } + + func testSubtractingReportingOverflow() { + NBKAssertSubtraction(T(1), T(0), Int(0), T(words:[ 1] as X)) + NBKAssertSubtraction(T(1), T(1), Int(0), T(words:[ 0] as X)) + NBKAssertSubtraction(T(1), T(2), Int(0), T(words:[~0] as X), true) + NBKAssertSubtraction(T(1), T(3), Int(0), T(words:[~1] as X), true) + } + + func testSubtractingAtIndex() { + NBKAssertSubtraction(T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[~1, ~2, ~3, ~0] as X)) + NBKAssertSubtraction(T(words:[ 0, ~0, ~0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[~0, ~3, ~3, ~0] as X)) + NBKAssertSubtraction(T(words:[ 0, 0, ~0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[~0, ~2, ~4, ~0] as X)) + NBKAssertSubtraction(T(words:[ 0, 0, 0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(0), T(words:[~0, ~2, ~3, ~1] as X)) + + NBKAssertSubtraction(T(words:[~0, ~0, ~0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[~0, ~1, ~2, ~3] as X)) + NBKAssertSubtraction(T(words:[ 0, ~0, ~0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[ 0, ~1, ~2, ~3] as X)) + NBKAssertSubtraction(T(words:[ 0, 0, ~0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[ 0, ~0, ~3, ~3] as X)) + NBKAssertSubtraction(T(words:[ 0, 0, 0, ~0] as X), T(words:[ 1, 2, 3, 0] as X), Int(1), T(words:[ 0, ~0, ~2, ~4] as X)) + } + + func testSubtractingAtIndexReportingOverflow() { + NBKAssertSubtraction(T(words:[ 1, 2, 3, 0] as X), T(words:[ 4, 5, 0, 0] as X), Int(0), T(words:[~2, ~3, 2, 0] as X)) + NBKAssertSubtraction(T(words:[ 1, 2, 3, 0] as X), T(words:[ 4, 5, 0, 0] as X), Int(1), T(words:[ 1, ~1, ~2, 0] as X), true) + NBKAssertSubtraction(T(words:[ 1, 2, 3, 0] as X), T(words:[ 4, 5, 0, 0] as X), Int(2), T(words:[ 1, 2, ~0, ~5] as X), true) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testSubtractingDigit() { + NBKAssertSubtractionByDigit(T(3), UInt(0), Int(0), T(3)) + NBKAssertSubtractionByDigit(T(3), UInt(1), Int(0), T(2)) + NBKAssertSubtractionByDigit(T(3), UInt(2), Int(0), T(1)) + NBKAssertSubtractionByDigit(T(3), UInt(3), Int(0), T(0)) + } + + func testSubtractingDigitReportingOverflow() { + NBKAssertSubtractionByDigit(T(1), UInt(0), Int(0), T(words:[ 1] as X)) + NBKAssertSubtractionByDigit(T(1), UInt(1), Int(0), T(words:[ 0] as X)) + NBKAssertSubtractionByDigit(T(1), UInt(2), Int(0), T(words:[~0] as X), true) + NBKAssertSubtractionByDigit(T(1), UInt(3), Int(0), T(words:[~1] as X), true) + } + + func testSubtractingDigitAtIndex() { + NBKAssertSubtractionByDigit(T(words:[~0, ~0, ~0, ~0] as X), UInt(3), Int(0), T(words:[~3, ~0, ~0, ~0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 0, ~0, ~0, ~0] as X), UInt(3), Int(0), T(words:[~2, ~1, ~0, ~0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 0, 0, ~0, ~0] as X), UInt(3), Int(0), T(words:[~2, ~0, ~1, ~0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 0, 0, 0, ~0] as X), UInt(3), Int(0), T(words:[~2, ~0, ~0, ~1] as X)) + + NBKAssertSubtractionByDigit(T(words:[~0, ~0, ~0, ~0] as X), UInt(3), Int(1), T(words:[~0, ~3, ~0, ~0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 0, ~0, ~0, ~0] as X), UInt(3), Int(1), T(words:[ 0, ~3, ~0, ~0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 0, 0, ~0, ~0] as X), UInt(3), Int(1), T(words:[ 0, ~2, ~1, ~0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 0, 0, 0, ~0] as X), UInt(3), Int(1), T(words:[ 0, ~2, ~0, ~1] as X)) + } + + func testSubtractingDigitAtIndexReportingOverflow() { + NBKAssertSubtractionByDigit(T(words:[ 1, 2, 3, 0] as X), UInt(5), Int(0), T(words:[~3, 1, 3, 0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 1, 2, 3, 0] as X), UInt(5), Int(1), T(words:[ 1, ~2, 2, 0] as X)) + NBKAssertSubtractionByDigit(T(words:[ 1, 2, 3, 0] as X), UInt(5), Int(2), T(words:[ 1, 2, ~1, 0] as X), true) + NBKAssertSubtractionByDigit(T(words:[ 1, 2, 3, 0] as X), UInt(5), Int(3), T(words:[ 1, 2, 3, ~4] as X), true) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x -= 0) + XCTAssertNotNil(x.subtract(0, at: 0)) + XCTAssertNotNil(x.subtractReportingOverflow(0, at: 0)) + + XCTAssertNotNil(x - 0) + XCTAssertNotNil(x.subtracting(0, at: 0)) + XCTAssertNotNil(x.subtractingReportingOverflow(0, at: 0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Subtraction x Assertions +//*============================================================================* + +private func NBKAssertSubtraction( +_ lhs: T, _ rhs: T, _ index: Int, _ partialValue: T, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if !overflow, index.isZero { + XCTAssertEqual( lhs - rhs, partialValue, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs -= rhs; return lhs }(), partialValue, file: file, line: line) + + XCTAssertEqual(lhs.subtracting(rhs, at: Int.zero), partialValue, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.subtract(rhs, at: Int.zero); return lhs }(), partialValue, file: file, line: line) + } + //=------------------------------------------= + guard let lhs = lhs as? UIntXL, let rhs = rhs as? UIntXL, let partialValue = partialValue as? UIntXL else { + return precondition(T.isSigned) + } + //=------------------------------------------= + if index.isZero { + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs).partialValue, partialValue, file: file, line: line) + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs).overflow, overflow, file: file, line: line) + + XCTAssertEqual({ var x = lhs; let _ = x.subtractReportingOverflow(rhs); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = lhs; let o = x.subtractReportingOverflow(rhs); return o }(), overflow, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs, at: index).partialValue, partialValue, file: file, line: line) + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs, at: index).overflow, overflow, file: file, line: line) + + XCTAssertEqual({ var x = lhs; let _ = x.subtractReportingOverflow(rhs, at: index); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = lhs; let o = x.subtractReportingOverflow(rhs, at: index); return o }(), overflow, file: file, line: line) +} + +private func NBKAssertSubtractionByDigit( +_ lhs: T, _ rhs: T.Digit, _ index: Int, _ partialValue: T, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if !overflow, index.isZero { + XCTAssertEqual( lhs - rhs, partialValue, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs -= rhs; return lhs }(), partialValue, file: file, line: line) + + XCTAssertEqual(lhs.subtracting(rhs, at: Int.zero), partialValue, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs.subtract(rhs, at: Int.zero); return lhs }(), partialValue, file: file, line: line) + } + //=------------------------------------------= + guard let lhs = lhs as? UIntXL, let rhs = rhs as? UIntXL.Digit, let partialValue = partialValue as? UIntXL else { + return precondition(T.isSigned) + } + //=------------------------------------------= + if index.isZero { + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs).partialValue, partialValue, file: file, line: line) + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs).overflow, overflow, file: file, line: line) + + XCTAssertEqual({ var x = lhs; let _ = x.subtractReportingOverflow(rhs); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = lhs; let o = x.subtractReportingOverflow(rhs); return o }(), overflow, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs, at: index).partialValue, partialValue, file: file, line: line) + XCTAssertEqual(lhs.subtractingReportingOverflow(rhs, at: index).overflow, overflow, file: file, line: line) + + XCTAssertEqual({ var x = lhs; let _ = x.subtractReportingOverflow(rhs, at: index); return x }(), partialValue, file: file, line: line) + XCTAssertEqual({ var x = lhs; let o = x.subtractReportingOverflow(rhs, at: index); return o }(), overflow, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Text.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Text.swift new file mode 100644 index 00000000..5e208c91 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Text.swift @@ -0,0 +1,1206 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Text x UIntXL +//*============================================================================* +//=----------------------------------------------------------------------------= +// NOTE: See the for-each-radix section for more encoding tests. +//=----------------------------------------------------------------------------= + +final class NBKFlexibleWidthTestsOnTextAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + /// - Note: Its description is not as lenient as its string literal. + func testFromDescription() { + NBKAssertFromDescription(T?( 10), "10") + NBKAssertFromDescription(T?( 10), "+10") + NBKAssertFromDescription(T?(nil), "-10") + NBKAssertFromDescription(T?(nil), " 10") + NBKAssertFromDescription(T?(nil), "0x10") + NBKAssertFromDescription(T?(nil), "+0x10") + NBKAssertFromDescription(T?(nil), "-0x10") + NBKAssertFromDescription(T?(nil), " 0x10") + } + + func testInstanceDescriptionUsesRadix10() { + XCTAssertEqual("10", T(10).description) + XCTAssertEqual("10", String(describing: T(10))) + } + + func testMetaTypeDescriptionIsSimple() { + XCTAssertEqual("UIntXL", T.description) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Decoding + //=------------------------------------------------------------------------= + + func testDecodingUnalignedStringsIsOK() { + NBKAssertDecodingText(T(1), 10, "1") + NBKAssertDecodingText(T(1), 16, "1") + } + + func testDecodingRadixLiteralAsNumber() { + NBKAssertDecodingText(T(33), 36, "0x") + NBKAssertDecodingText(T(24), 36, "0o") + NBKAssertDecodingText(T(11), 36, "0b") + + NBKAssertDecodingText(T(33), 36, "+0x") + NBKAssertDecodingText(T(24), 36, "+0o") + NBKAssertDecodingText(T(11), 36, "+0b") + } + + func testDecodingRadixLiteralAsRadixReturnsNil() { + NBKAssertDecodingText(T?.none, 10, "0x10") + NBKAssertDecodingText(T?.none, 10, "0o10") + NBKAssertDecodingText(T?.none, 10, "0b10") + + NBKAssertDecodingText(T?.none, 10, "+0x10") + NBKAssertDecodingText(T?.none, 10, "+0o10") + NBKAssertDecodingText(T?.none, 10, "+0b10") + } + + func testDecodingStringsWithAndWithoutSign() { + NBKAssertDecodingText(T(1234567890), 10, "1234567890") + NBKAssertDecodingText(T(1234567890), 10, "+1234567890") + } + + func testDecodingStrategyIsCaseInsensitive() { + NBKAssertDecodingText(T(0xabcdef), 16, "abcdef") + NBKAssertDecodingText(T(0xABCDEF), 16, "ABCDEF") + NBKAssertDecodingText(T(0xaBcDeF), 16, "aBcDeF") + NBKAssertDecodingText(T(0xAbCdEf), 16, "AbCdEf") + } + + func testDecodingPrefixingZerosHasNoEffect() { + let zero = String(repeating: "0", count: 256) + "0" + let one = String(repeating: "0", count: 256) + "1" + + for radix in 02 ... 36 { + NBKAssertDecodingText(T(0), radix, zero) + NBKAssertDecodingText(T(1), radix, one ) + } + } + + func testDecodingInvalidCharactersReturnsNil() { + NBKAssertDecodingText(T?.none, 16, "/") + NBKAssertDecodingText(T?.none, 16, "G") + + NBKAssertDecodingText(T?.none, 10, "/") + NBKAssertDecodingText(T?.none, 10, ":") + + NBKAssertDecodingText(T?.none, 10, String(repeating: "1", count: 19) + "/") + NBKAssertDecodingText(T?.none, 10, String(repeating: "1", count: 19) + ":") + } + + func testDecodingStringsWithoutDigitsReturnsNil() { + NBKAssertDecodingText(T?.none, 10, "") + NBKAssertDecodingText(T?.none, 10, "+") + NBKAssertDecodingText(T?.none, 10, "-") + NBKAssertDecodingText(T?.none, 10, "~") + + NBKAssertDecodingText(T?.none, 16, "") + NBKAssertDecodingText(T?.none, 16, "+") + NBKAssertDecodingText(T?.none, 16, "-") + NBKAssertDecodingText(T?.none, 16, "~") + } + + func testDecodingValuesOutsideOfRepresentableRangeReturnsNil() { + for radix in 02 ... 36 { + NBKAssertDecodingText(T?.none, radix, "-1") + } + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Text x For Each Radix x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnTextForEachRadixAsUIntXL: XCTestCase { + + typealias T = UIntXL + + //=------------------------------------------------------------------------= + // MARK: State + //=------------------------------------------------------------------------= + + /// The bit pattern: `0xfffefdfcfbfaf9f8...0706050403020100`. + static let ascending = T(x64:[ + 0x0706050403020100, 0x0f0e0d0c0b0a0908, 0x1716151413121110, 0x1f1e1d1c1b1a1918, + 0x2726252423222120, 0x2f2e2d2c2b2a2928, 0x3736353433323130, 0x3f3e3d3c3b3a3938, + 0x4746454443424140, 0x4f4e4d4c4b4a4948, 0x5756555453525150, 0x5f5e5d5c5b5a5958, + 0x6766656463626160, 0x6f6e6d6c6b6a6968, 0x7776757473727170, 0x7f7e7d7c7b7a7978, + 0x8786858483828180, 0x8f8e8d8c8b8a8988, 0x9796959493929190, 0x9f9e9d9c9b9a9998, + 0xa7a6a5a4a3a2a1a0, 0xafaeadacabaaa9a8, 0xb7b6b5b4b3b2b1b0, 0xbfbebdbcbbbab9b8, + 0xc7c6c5c4c3c2c1c0, 0xcfcecdcccbcac9c8, 0xd7d6d5d4d3d2d1d0, 0xdfdedddcdbdad9d8, + 0xe7e6e5e4e3e2e1e0, 0xefeeedecebeae9e8, 0xf7f6f5f4f3f2f1f0, 0xfffefdfcfbfaf9f8]) + + /// The bit pattern: `0x0001020304050607...f8f9fafbfcfdfeff`. + static let descending = T(x64:[ + 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7, 0xe8e9eaebecedeeef, 0xe0e1e2e3e4e5e6e7, + 0xd8d9dadbdcdddedf, 0xd0d1d2d3d4d5d6d7, 0xc8c9cacbcccdcecf, 0xc0c1c2c3c4c5c6c7, + 0xb8b9babbbcbdbebf, 0xb0b1b2b3b4b5b6b7, 0xa8a9aaabacadaeaf, 0xa0a1a2a3a4a5a6a7, + 0x98999a9b9c9d9e9f, 0x9091929394959697, 0x88898a8b8c8d8e8f, 0x8081828384858687, + 0x78797a7b7c7d7e7f, 0x7071727374757677, 0x68696a6b6c6d6e6f, 0x6061626364656667, + 0x58595a5b5c5d5e5f, 0x5051525354555657, 0x48494a4b4c4d4e4f, 0x4041424344454647, + 0x38393a3b3c3d3e3f, 0x3031323334353637, 0x28292a2b2c2d2e2f, 0x2021222324252627, + 0x18191a1b1c1d1e1f, 0x1011121314151617, 0x08090a0b0c0d0e0f, 0x0001020304050607]) + + //=------------------------------------------------------------------------= + // MARK: Assertions + //=------------------------------------------------------------------------= + + func check(_ integer: T, radix: Int, ascii: String, file: StaticString = #file, line: UInt = #line) { + var encoded = String(ascii.drop(while:{ $0 == "0" })) + if encoded.isEmpty { + encoded.append(contentsOf: ascii.suffix(1)) + } + + NBKAssertDecodingText(integer, radix, ascii, file: file, line: line) + NBKAssertDecodingText(integer, radix, encoded, file: file, line: line) + NBKAssertEncodingText(integer, radix, true, encoded.uppercased(), file: file, line: line) + NBKAssertEncodingText(integer, radix, false, encoded.lowercased(), file: file, line: line) + } + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testImportantValues() { + for radix in 2 ... 36 { + self.check(T(0), radix: radix, ascii: "0") + self.check(T(1), radix: radix, ascii: "1") + } + + for radix in 02 ... 36 { + NBKAssertDecodingText(T?( 0), radix, "0") + NBKAssertDecodingText(T?( 0), radix, "+0") + NBKAssertDecodingText(T?( 0), radix, "-0") + NBKAssertDecodingText(T?( 1), radix, "1") + NBKAssertDecodingText(T?( 1), radix, "+1") + NBKAssertDecodingText(T?(nil), radix, "-1") + } + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Ascending, Descending + //=------------------------------------------------------------------------= + + func test02() { + self.check(Self.ascending, radix: 02, ascii: """ + 1111111111111110111111011111110011111011111110101111100111111000\ + 1111011111110110111101011111010011110011111100101111000111110000\ + 1110111111101110111011011110110011101011111010101110100111101000\ + 1110011111100110111001011110010011100011111000101110000111100000\ + 1101111111011110110111011101110011011011110110101101100111011000\ + 1101011111010110110101011101010011010011110100101101000111010000\ + 1100111111001110110011011100110011001011110010101100100111001000\ + 1100011111000110110001011100010011000011110000101100000111000000\ + 1011111110111110101111011011110010111011101110101011100110111000\ + 1011011110110110101101011011010010110011101100101011000110110000\ + 1010111110101110101011011010110010101011101010101010100110101000\ + 1010011110100110101001011010010010100011101000101010000110100000\ + 1001111110011110100111011001110010011011100110101001100110011000\ + 1001011110010110100101011001010010010011100100101001000110010000\ + 1000111110001110100011011000110010001011100010101000100110001000\ + 1000011110000110100001011000010010000011100000101000000110000000\ + 0111111101111110011111010111110001111011011110100111100101111000\ + 0111011101110110011101010111010001110011011100100111000101110000\ + 0110111101101110011011010110110001101011011010100110100101101000\ + 0110011101100110011001010110010001100011011000100110000101100000\ + 0101111101011110010111010101110001011011010110100101100101011000\ + 0101011101010110010101010101010001010011010100100101000101010000\ + 0100111101001110010011010100110001001011010010100100100101001000\ + 0100011101000110010001010100010001000011010000100100000101000000\ + 0011111100111110001111010011110000111011001110100011100100111000\ + 0011011100110110001101010011010000110011001100100011000100110000\ + 0010111100101110001011010010110000101011001010100010100100101000\ + 0010011100100110001001010010010000100011001000100010000100100000\ + 0001111100011110000111010001110000011011000110100001100100011000\ + 0001011100010110000101010001010000010011000100100001000100010000\ + 0000111100001110000011010000110000001011000010100000100100001000\ + 0000011100000110000001010000010000000011000000100000000100000000 + """) + + self.check(Self.descending, radix: 02, ascii: """ + 0000000000000001000000100000001100000100000001010000011000000111\ + 0000100000001001000010100000101100001100000011010000111000001111\ + 0001000000010001000100100001001100010100000101010001011000010111\ + 0001100000011001000110100001101100011100000111010001111000011111\ + 0010000000100001001000100010001100100100001001010010011000100111\ + 0010100000101001001010100010101100101100001011010010111000101111\ + 0011000000110001001100100011001100110100001101010011011000110111\ + 0011100000111001001110100011101100111100001111010011111000111111\ + 0100000001000001010000100100001101000100010001010100011001000111\ + 0100100001001001010010100100101101001100010011010100111001001111\ + 0101000001010001010100100101001101010100010101010101011001010111\ + 0101100001011001010110100101101101011100010111010101111001011111\ + 0110000001100001011000100110001101100100011001010110011001100111\ + 0110100001101001011010100110101101101100011011010110111001101111\ + 0111000001110001011100100111001101110100011101010111011001110111\ + 0111100001111001011110100111101101111100011111010111111001111111\ + 1000000010000001100000101000001110000100100001011000011010000111\ + 1000100010001001100010101000101110001100100011011000111010001111\ + 1001000010010001100100101001001110010100100101011001011010010111\ + 1001100010011001100110101001101110011100100111011001111010011111\ + 1010000010100001101000101010001110100100101001011010011010100111\ + 1010100010101001101010101010101110101100101011011010111010101111\ + 1011000010110001101100101011001110110100101101011011011010110111\ + 1011100010111001101110101011101110111100101111011011111010111111\ + 1100000011000001110000101100001111000100110001011100011011000111\ + 1100100011001001110010101100101111001100110011011100111011001111\ + 1101000011010001110100101101001111010100110101011101011011010111\ + 1101100011011001110110101101101111011100110111011101111011011111\ + 1110000011100001111000101110001111100100111001011110011011100111\ + 1110100011101001111010101110101111101100111011011110111011101111\ + 1111000011110001111100101111001111110100111101011111011011110111\ + 1111100011111001111110101111101111111100111111011111111011111111 + """) + } + + func test03() { + self.check(Self.ascending, radix: 03, ascii: """ + 0000000000000000000000000000000000000000000000000001011122001202\ + 0221000010120021121012122122121210201121000021000121212010111102\ + 0021022202211121121121221212000020201221122210202201001002201010\ + 0210001212020121021021121001210100100102120102122200201001202102\ + 2220222111112021200221211122210111211012110122021212001101101012\ + 0200211111121022021211100122022012211112112221002121112202200001\ + 1001122202020122210212021001020200222212112100211020020010002221\ + 0111000010011011101010021210201220102122102122212202102012220100\ + 0111020201112002211002010001100110020220111111012101100222010221\ + 0010122122022201020000102121202021200201200211001212202010110021\ + 2001010202202101112000210220201111022010220200012021000020111021\ + 2201012002120201120221122221012002222200122120210000120121000201\ + 2012211022021200001122102120002110221102210110111021200002120202\ + 2010012002002102202002201200210100102202220110101222010000222022\ + 0200112200201010002020101100200110010000000002001202111210200020\ + 0002120001222001110002220220221011110011011012201210101122122001\ + 2111021020102211121020000002111101220000201210122212002012102220\ + 1110200122122112012100001022010221010222101020220010000121012012\ + 0010010122111111120110221020002211102201221020121121212111201100\ + 0200121221120002212120101220100120101121122112221220012112011121\ + 0121001121010221102001120121101000020200001000211102020110221110 + """) + + self.check(Self.descending, radix: 03, ascii: """ + 0000000000000000000000000000000000000000000000000000000000000100\ + 1201120210220100110000101022020200210120211212120010111000100200\ + 1201120210200222221112211112120122111002022121212221220020020021\ + 1211112200121202200221110201112022200111011002001111211001001210\ + 2220102000012100211210021120211221200212210011220221221210221212\ + 2222022220122111000220122201210100221211021220102010112022011111\ + 0121021201001110200122102112201202022222200221000101120200212101\ + 1010021021022221120101211200201110000211111122201202020202110221\ + 0022120111200020110102012011210110000211200010220002101111120101\ + 1221102201020120002022010122120111111211222012011211212110222012\ + 1202220212201211110122201021001011010112010211112010202102100001\ + 1201212220101111022210120202211012001102022221101101221222200111\ + 0101010020020220000112200212022001021010021100102210101022210211\ + 1202021010021102110001202120201000202122002011122102011220111101\ + 1012211121220210021002212210112100210201120111010221022120001212\ + 1222110100200211122221210100020221110011222001202222000211010100\ + 1122110212221111011200112012012002220201002201222110102200111201\ + 0111111101220210011222012010020001021121201122201012021221210210\ + 2110011012222121222020020212110121100210220002222011101221021021\ + 0112202220101220011210212011210102200110100021221220200201110011\ + 0022000111200121201021102000112221002012210222221221112222201100 + """) + } + + func test04() { + self.check(Self.ascending, radix: 04, ascii: """ + 3333333233313330332333223321332033133312331133103303330233013300\ + 3233323232313230322332223221322032133212321132103203320232013200\ + 3133313231313130312331223121312031133112311131103103310231013100\ + 3033303230313030302330223021302030133012301130103003300230013000\ + 2333233223312330232323222321232023132312231123102303230223012300\ + 2233223222312230222322222221222022132212221122102203220222012200\ + 2133213221312130212321222121212021132112211121102103210221012100\ + 2033203220312030202320222021202020132012201120102003200220012000\ + 1333133213311330132313221321132013131312131113101303130213011300\ + 1233123212311230122312221221122012131212121112101203120212011200\ + 1133113211311130112311221121112011131112111111101103110211011100\ + 1033103210311030102310221021102010131012101110101003100210011000\ + 0333033203310330032303220321032003130312031103100303030203010300\ + 0233023202310230022302220221022002130212021102100203020202010200\ + 0133013201310130012301220121012001130112011101100103010201010100\ + 0033003200310030002300220021002000130012001100100003000200010000 + """) + + self.check(Self.descending, radix: 04, ascii: """ + 0000000100020003001000110012001300200021002200230030003100320033\ + 0100010101020103011001110112011301200121012201230130013101320133\ + 0200020102020203021002110212021302200221022202230230023102320233\ + 0300030103020303031003110312031303200321032203230330033103320333\ + 1000100110021003101010111012101310201021102210231030103110321033\ + 1100110111021103111011111112111311201121112211231130113111321133\ + 1200120112021203121012111212121312201221122212231230123112321233\ + 1300130113021303131013111312131313201321132213231330133113321333\ + 2000200120022003201020112012201320202021202220232030203120322033\ + 2100210121022103211021112112211321202121212221232130213121322133\ + 2200220122022203221022112212221322202221222222232230223122322233\ + 2300230123022303231023112312231323202321232223232330233123322333\ + 3000300130023003301030113012301330203021302230233030303130323033\ + 3100310131023103311031113112311331203121312231233130313131323133\ + 3200320132023203321032113212321332203221322232233230323132323233\ + 3300330133023303331033113312331333203321332233233330333133323333 + """) + } + + func test05() { + self.check(Self.ascending, radix: 05, ascii: """ + 0000000000000101011133132112303401331203113040334201212224114333\ + 1331210120311431302322401423134214144114302234223323124032013102\ + 2031310012312133044114114101403342401111141021424131121343010430\ + 1421121331201040013433442113440322214443111221044313323014144300\ + 0442200211013021440424413104144331034304433134022344442034220120\ + 0203022440403030041413132134201411232022143440134130244204021202\ + 4204221131331321003014044044023244032003434441023101312044413410\ + 1432032422222011101300422133144024022310244143301333333131313132\ + 1133101212222113330424040311111134211430243400332404421303012024\ + 3301033334140414340340314003013204313402213301322411212023034201\ + 2004134224142103031424130211110200431412144004241140022344304021\ + 2024422012034413242431014044023232132211032301042413413421403001\ + 0304124320331131120040124432124112202220433320304324003340021343\ + 1324223134224004424011000321223301220134021034313232023030324130 + """) + + self.check(Self.descending, radix: 05, ascii: """ + 0000000000000000000011112220410043202330011120133410031040004330\ + 4341221403222404433322102144041223114211314323343204434113224023\ + 4202133231041330002312141443032100300431040042214130113344324022\ + 0003033132111304421001413014203324242214223404240341232242231142\ + 3340214011113104001131004242024004221443142132444122344311101242\ + 1004023141340203330402132300004344144322442200321404111130230232\ + 3133343130231214411012031114143432214413020420233100440220432423\ + 2243141404410214044100142011212104313004030243322344322310333323\ + 3024401130130344314420430011223234330142032224324334134040231223\ + 3411402203220101304223402340422200404331110030013243131121203033\ + 4421222201121212122344111102000123003033403313011113442344310321\ + 0212040323210123133413431243330144102203032410432301243134312231\ + 0222420103420141120210200140403304423210100101323244203323144103\ + 2244421302202340120224210321141312243002114134133313000033010430 + """) + } + + func test06() { + self.check(Self.ascending, radix: 06, ascii: """ + 0000000000000000000000000000000000000001345131000552333115344121\ + 1214023443243324324333122442522233415252532225231130540122100214\ + 0215244235522514322330122325410454305413105211242412413243515420\ + 4031415411205525200543134520405500520504130422250301225525122255\ + 5304444554221253253024400132115002405214044033240245530335422552\ + 3230145401344324044315001345525133204253014235441544150342233311\ + 3102525333433242251435152053450224205545410400155320525214003341\ + 0114031334552553523440515235201104055151034451040431352324424022\ + 3220325011454332550413335135033252231132320134203510232401355331\ + 2020345410240441033104340125314154522445134135421334244051303551\ + 0152420450032004440445510515505305150554300514513545121304233402\ + 1512140511314534242423200345252352143342420322435054213022035002\ + 4325250215312305241230104233141315022325103343150130404400523320 + """) + + self.check(Self.descending, radix: 06, ascii: """ + 0000000000000000000000000000000000000000000001101244524030103050\ + 5531042315523235333525101305553312125110054220232435524352224142\ + 2053151321544434335040524214255145034313244420015104114444532130\ + 5131211403354545331043000404415555115552254524500234324052054544\ + 0212530234155222352503522355044401441443444123253343143251424324\ + 4134551510104424455502335515404533114302125220421213020520110411\ + 1504043310005143320344204330350455513552351141214450322440103324\ + 3125500135505231115445012513503141220340440111403544321144410454\ + 4434544550051012214002454222455235433415531502214521123242404320\ + 4014321430553334134451431214532201142053235043445501013550154325\ + 3024252321100454253441131350205155431304043512204000014004531004\ + 2034152112152200254215340255540550522204504133200444140500531431\ + 2233041532325315013225020141304435140311224252411541420101544143 + """) + } + + func test07() { + self.check(Self.ascending, radix: 07, ascii: """ + 0000000000000000000000000000000000000024653320130023336353601340\ + 0355512020400135330313404163116323361665214341655231546035543041\ + 3335061463602013225153316300026621432263543366545536433610205024\ + 3003025201644424044635410411626456311635136110623401315661102442\ + 0612331166566162241453601510216450625624416556453020643500526255\ + 4225530231005403046503563131246643640004650324634650424453045323\ + 3644226261554166110441022133064452150660600363500515360604100635\ + 1324126506201641562342434011560236352122640326266120664210323233\ + 2635011020024026201015103132011050236605005335425545336151120104\ + 5113112534231011226633116051366211215560241650222456652010032225\ + 3614546631516640255632303266244531025632554125633416523166131412\ + 3533422165650541466015660324101553116436025240606246521266532034 + """) + + self.check(Self.descending, radix: 07, ascii: """ + 0000000000000000000000000000000000000000000046215156341104144413\ + 6064621423661545444654615066360306060465143246516123400132545065\ + 2014515155412342351261361320435321015260445542345153424665323461\ + 0114416030513346553314263163630631425445505265616243343122362104\ + 2000460423064644315166540105254001105315016506520645232434362254\ + 4331411646406403010516610221633665334030662154232055411300246353\ + 0310563254056060056622336540260033560331003320163152232604433135\ + 4164235460542041401510521102142062156431435343046560332465042201\ + 6511235106510212216314244536164605241220642565660111156412634233\ + 6556106632453464235621424215600534606530001631160211606003002230\ + 1611605222100443162203206534603240202153655435353545022116362124\ + 6026410120242432506346633405306601261561020623142104244113610216 + """) + } + + func test08() { + self.check(Self.ascending, radix: 08, ascii: """ + 0000000000000000000003777757677476775371761737667537236374570760\ + 7376735573165752723643477156274470761341701577366735633366554730\ + 6575332565151722643503176354671462745311621437066134230360540700\ + 5773727557135672563342675553266454731261541276565332625352524650\ + 5172324551121642503202374751663446715231461136264531222344510620\ + 4370721543105612423042074150260440701201400775763727617336474570\ + 3567316535071562342701573346655432665151320635463126214330460540\ + 2765713527055532262541272545252424651121240475162324611322444510\ + 2164310521041502202400771743647416635071160334661523206314430460\ + 1362705513025452122240471142244410621041100174360721603306414430\ + 0561302505011422042100170340641402605011020034060120200300400400 + """) + + self.check(Self.descending, radix: 08, ascii: """ + 0000000000000000000000000020100301002406016040110240541403207017\ + 0401042204612025054134300621503307016436076200411042144411223047\ + 1202445212626055134274601423106315032466156340711643547417237077\ + 2004050220642105214435102224511323046516236501212445152425253127\ + 2605453226656135274575403026114331062546316641513246555433267157\ + 3407056234672165354735703627517337076576377002014050160441303207\ + 4210461242706215435076204431122345112626457142314651563447317237\ + 5012064250722245515236505232525353126656537302615453166455333267\ + 5613467256736275575377006034130361142706617443116254571463347317\ + 6415072264752325655537306635533367156736677603417056174471363347\ + 7216475272766355735677607437136375172766757743717657577477377377 + """) + } + + func test09() { + self.check(Self.ascending, radix: 09, ascii: """ + 0000000000000000000000000000000000000000000000000000000001148052\ + 2700350753557855364700701776344207282747547855006657583681032633\ + 2305521723753171031251258063167286874467627748714735418255041335\ + 2074453825431826574548707748260131582218725231220885470736203087\ + 1400313433325365637837878236581014221462732101313226444171328127\ + 0357828120037766762162405566340761122671460726644263820167006437\ + 8116252152758716288057670051702165738250048376073842713437602522\ + 6316207266265071038281335810086820480633066340613100002052453606\ + 0250186140282683440413565334856174236384536002441800653585065386\ + 4361857517003812712833680301716503118444513836084381836547774640\ + 2055750277635631634757585617514717047127361517330220030742213843 + """) + + self.check(Self.descending, radix: 09, ascii: """ + 0000000000000000000000000000000000000000000000000000000000000010\ + 5152381040033822071675550343032051523628845745518432277787806207\ + 5448055262742146861413204473105386360170753246757625704827853855\ + 8828657402658171085425636346814417251043618375652288627011520771\ + 3323728751175064302444865222242708514606412164713024603802344511\ + 5738121606811851445486515477386552825654418637034115124463672301\ + 5178634428352273504228734185861411106226015625261233240383338724\ + 5223324240167663067806457215644135747823232783470721514127276055\ + 5841062458771022740486168802411048425844150465162821081873380451\ + 1444182315816320124764863525772373135877866225417323802864357237\ + 1568635615376471261330785662140408014617637360487065728857488640 + """) + } + + func test10() { + self.check(Self.ascending, radix: 10, ascii: """ + 0000000000000000000000032316509077753586139510713445660514514047\ + 1715800934968659014776021432245405574123404729692361840203777454\ + 0863807743939745614194869975427379141886998502749960224378577364\ + 6750786158629119897527698459159582903277348091197804306308450975\ + 2765897157258671077139706248797954495766510537726453385451362891\ + 2932640350906509210810910107747204614412263847494852734365334510\ + 5797020149055603954704727773430317796884279167058635246262041734\ + 9145786264563977273862044757186140910253489061210709169291375411\ + 8235589361595220880511748744523688475088623430039909767486996242\ + 6348425792929710270231641017897005896324246640151098893336183040 + """) + + self.check(Self.descending, radix: 10, ascii: """ + 0000000000000000000000000000496993557421161204163243009437446396\ + 9310896219871662288678253814305983104785527242321753388930859433\ + 0932284445862203797761045073664730366928240142078351838709159365\ + 4245305591568630492124408336898055480790220185594414336311305186\ + 5615046227503033628676752271565095933109248377684204700624161099\ + 9460398201284924128155924134321292864244193101990764869167297695\ + 2280785510275422238003732540719940795979897949667308357456420122\ + 4430197246959039185181992218946191962058782195636399032805876159\ + 1937103770751746973746316925269816124638211869823911785029642701\ + 0987117809205722959373004300581599055823946915702512166260047615 + """) + } + + func test11() { + self.check(Self.ascending, radix: 11, ascii: """ + 0000000000000000000000000000000000000000000000010142aa3554859615\ + 1a9204496a56113782737a0530594194878213854265484228a2873210376102\ + 298531554729267773485a52aaa2030350391963a7a0a94819183a184061767a\ + a1664196a92a29124a90906677a6159283540713930a23461662230751976003\ + 75aa406a38a465902249a525645153a635a40a420899916a90a1749213325274\ + 6766792593268189a459a23695332111336a2574023146139a17034537465a24\ + 8967a2a50a37a69914126a360951448575372782095382a02084543002870940\ + 85532153a572629110a97679073778890291691419a246a95a6016478938298a\ + 358425533763a551898a379424822a252aa411a696485496052a6871743a226a\ + 8989647385195622111666334615228957638330392039898693611430034583 + """) + + self.check(Self.descending, radix: 11, ascii: """ + 0000000000000000000000000000000000000000000000000000256148a85586\ + 5197664763a413508459939466315799165a6237763aa375593223a736658a62\ + 6175a059a7751a78641a7a475619616477939520a087332893696097491542a0\ + 32141834910a431662128201852a11559a110337a57054a296643718815a7a80\ + 48479962aa316851a2904aa35279872922828167a735214a27215a821861a384\ + 99815a0961a3737601288254235997668057936329799a941615802815674803\ + 25786a7644882756447532455a8a3a35981a95a6909a13497286502490619a17\ + 1a77888724a210a717362256366a598950960902066765804a99481685943069\ + 59110458713a51298801a11123297018992a5501098a28a26006692109193391\ + a16a79092aa045204411a34032199992178aa6827439a86a4a1162545251105a + """) + } + + func test12() { + self.check(Self.ascending, radix: 12, ascii: """ + 00001b9367266a6039066116339183036aaa985742938485bbb3a46470645276\ + 569234baa5161788742348681a4a5b25ba61622633b09273b03b9aaa7514aa58\ + 900baa9a74852ab0219481b21a86a3153bab534868478662a6191b1659b54964\ + ab9654b6430343071b655848847330017058b16480bb191b0985b8521152b521\ + 563996041b3a74992b7126029326661485b6632a381a4ab4a820460396996731\ + 1955a0b949642455a94aa27512b620a30373879b06207879078319104b12b4b9\ + b2ba94a962459429a746627b83089334822b767922152b60a66b497450a07244\ + b845b1558994981851b953005363a121880435bb95b546ab1558447212026a12\ + 954b5492aa0367a34a0a961a50ba9a07b6279269932a4957a644a2a3a3920540 + """) + + self.check(Self.descending, radix: 12, ascii: """ + 00000000076b918968899b991b3a0b667713391937b3bb902301ab6145a77307\ + 44a2b60b437594576b487310178a094b5808bb63727175a001311367a6b15b60\ + a32b64505a7714b4726537456122412432166973a068b703039439a92559b5b6\ + 5b0a431247a475b7b73780620429b5646b5980809950201652a5a17013a53004\ + 9278712658818566b19311073b683072337992902a246221355872288749aa1a\ + 8b591341aaba72b3b98a0799b919741387205aa722a5a05582862a92506ba89b\ + a307a1a27768ba2575796b18278b74a250523680499a1a60492b1910ba644782\ + 6784970931559000310546aba16a418a4827544331254b700900bb405448b2a4\ + 4b093020088bb2535b47963b7b44608a93421b127bb07b00246477a7b8115053 + """) + } + + func test13() { + self.check(Self.ascending, radix: 13, ascii: """ + 000000000000000000000031cb7486735908c0144bc1018ac182c82a930a12ca\ + 74aa7825455c0218a1479ca12843cb94baa0938378c1c8384b19b34340a64b01\ + 4c927b86217b9a059379c40089c4314b035b5c702c8371c7c80104445bc99b56\ + 057a91abc9acb1bc37950647b72045a5a647587b15c865bb75c2380191829a66\ + 04a1184400818b29b9513b8c59490494649a18069b449c472c2366c76a2ca852\ + 5096cc27207409700b2a636668139b428455c9a6ac67131b4589833577743c3a\ + 7a091a293275c628b8a06625cb2a15734b58b3a57163a48014a7a5c277499614\ + 79955285c36bc06b629543773288158648aa581166a042608899014254840857\ + 15273b93212a908443abc9abc7929ba5810113319924a7468970130052605289 + """) + + self.check(Self.descending, radix: 13, ascii: """ + 000000000000000000000000001500b062c1244a5ca682353200a96937353c93\ + 73069a0b203a0697c45513ab9487a7205bb57cc5c425a5c032a2474a01bc3aa7\ + 7990173264abb8b83613121b5528156c4048b81422ac426709bccc65a508b4cb\ + 132b977345a9202198a9c32785c770890b69240b96ca5b132b8b9b817411a933\ + 4b72342699707c6b5c874c92ab31903c758988696cca9690145b772b03085bc3\ + 169a4bc0c135baab68558c0798367ba3406b38007b90c8885160454934686c89\ + 4cb56950cba1887a6a20b95b1c99c6b275100512542006c230c4193161a27012\ + 95b489091b11513a7b6aa93691a756cb65c77ca95668543158b357ca8ab95a44\ + a00348774316caaac9b21502a3302702c852a8bb56b24b5400628a24276750bc + """) + } + + func test14() { + self.check(Self.ascending, radix: 14, ascii: """ + 00000000000000000000000000000000000000ad0745312ac38003406c77772a\ + c5d337dc56d71b0120a8035c347cd412ba206c7a19b3638983ad6c7dac8866db\ + ad3165c94d93a13248c199cda6773520749b9430c797c2bb0d8ca867ba5a063b\ + 83d226939c0cbd8ab945b687021c84a90d7ba0d68cd37869a55260d1d780666b\ + 0b6a3a99600cd5b1d80b84cc30bd74702723a1126cbdb5a42c285669194da766\ + c63c8d6d1aad3cc15dda115b2445580577049b2b7b818a839a3d0713a25586d3\ + 109b2a74bb9cb5947074d06003a7d8559a8ab638c511c84c158d5c7033b7385d\ + 777b7d6c35b83b7c4a497aa9b859dc77b943581b1799d547b62548548666b945\ + 8d240951c39596c82589a5602b65a7c3b356a46269456953341674c2567b81c4 + """) + + self.check(Self.descending, radix: 14, ascii: """ + 000000000000000000000000000000000000000000665b20da8c012072742a9c\ + a5cd039c351d1954c650a78d38b82408a4277196aba9762211d09d8cd8b0d860\ + 6a3a66d5813834054475593121b4b9b0413200c31c0a2b0dba384d9032706145\ + d308b314144dacdd01dd8587897b13064dbc82a519ca81a734516c2298c2880a\ + 78c76978d6386d10859b60bb745899c01badadda1999d5b791193187c567c0a8\ + 32a2abc1cd43d1c3560bba8d56b67cab62bcd597b554a3d9b2ac51adc018d6cc\ + 80c0126414d43729179abd98859db7a875258b438c6b3a2a285d3786ddb0ad49\ + 5ba3add41a36735295c13053243d4a14dd747ac3353a4dd77b9314a9c9a79560\ + 6101643ad12c8242bac710666c8139696c146dd4da84974da56d48c94dbb007d + """) + } + + func test15() { + self.check(Self.ascending, radix: 15, ascii: """ + 0000000000000000000000000000000000000000000000000001adcc42d77564\ + 2e8d25576598e679706b39b634284eb4323514682a6a176bc422a0b453010958\ + 11db137066d571a2b91ec47eb29e5870c08bb8759a29eae1e60de477c04c2c97\ + a272774aaa2573b20764ea2a18c62d7c3660ec0387a7b658d71e5d9dc14245d0\ + 163d05e294dac37d9a00339a9b41ee29b3c604d4350739ee6c2617a77c226325\ + 8d6ca4cd40eb15b65a6341963a35035c8441616e6c21e1ec9d1bd1e3ed0a7c5b\ + 349c68802a1365081776371784a3c99b4ab7774eaa850176c7e9d1c8cda75827\ + 5e4ab4757030038b383714cd32c87c560ab2ecb8d102219ec16d0616544bcb2b\ + 651732d918a54ee364a155a488725ac7ce563e994b90e86e485ad50d52e0aab0 + """) + + self.check(Self.descending, radix: 15, ascii: """ + 0000000000000000000000000000000000000000000000000000000152b2d1a6\ + b8a8c0121657243d73087ce18b51dc75b4205004346095046c5560a817deba1c\ + d4a5a3105bc83eb096390746c90c20224a8317a34198e7cb73c7e970c60b5c74\ + 6a7d68177d9dd4e2c75c15d13b1646d63a900d38b4dc5286319dbb87c4a62e54\ + bd6d6d4d86509dd7036a27ab6d0bb6807483e90ebc70d57282906edbb53123b3\ + 9129135e549279d96ae4b2a1c7147cc03e4b73a279854b5d2a009b6de5301ad4\ + 059d1ae0989433c36c9bbee5a3645c426e40848de409cd82d902da7de45c0bb2\ + ab154e42536bca71849298d982c69e34e86a6a8b20990845809947073d753ba4\ + 370db27a2d22de47e12ab6e298b283e65b3d8b42e273650b315020dc1aa22960 + """) + } + + func test16() { + self.check(Self.ascending, radix: 16, ascii: """ + fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0\ + dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0\ + bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a0\ + 9f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786858483828180\ + 7f7e7d7c7b7a797877767574737271706f6e6d6c6b6a69686766656463626160\ + 5f5e5d5c5b5a595857565554535251504f4e4d4c4b4a49484746454443424140\ + 3f3e3d3c3b3a393837363534333231302f2e2d2c2b2a29282726252423222120\ + 1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100 + """) + + self.check(Self.descending, radix: 16, ascii: """ + 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\ + 202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f\ + 404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f\ + 606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f\ + 808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\ + a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf\ + c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf\ + e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff + """) + } + + func test17() { + self.check(Self.ascending, radix: 17, ascii: """ + 0000000000124b16c3g69bbbag36b77367c8366826a1260aafe896c41e5bebd6\ + eff1edf76b5c850269d547g2993fg898a7eg88g8db235g6c407d4898b5a17d05\ + 9g1d0fc9bgf991cagd36gae0bag2bg730e02b8265dg2e55825g7cdfe2fgedcg1\ + ba3dcc62916e6d11ggf6c160e48154efaf86ce618584dba7d1049ge226f62945\ + cgde056dffgb718cb2211bg5g72g77d5agd7e6b055e6b4ge71gg2e56be45c585\ + e31a98e65adc1c4560b001595gee6a7ec3cdgfb6248a0e351c5fa7gd40bc4afd\ + 2cddf99e175db6fgf31545e48gfb055b4g39cca53b5a97f743922d73b7afb7d7\ + 4928154d92b20gg7992e38cb96c1dd4bea7c7728fgb1127e0e47469feag585g0 + """) + + self.check(Self.descending, radix: 17, ascii: """ + 0000000000000017ce9c05e067e38a806859ca9f32f4efb5bbc0b1443434a7fe\ + 11f6g3f2g2a7bd55278c6b700309c5bge3dead4e678ab3f9a664703f66f716cg\ + 5b0f53e1655cc321011f1bb33625b5d44580930a9687c4b2926aa7c1gcbc4g63\ + 7c70abfcb0f4bdcfcf7174c446a2417b77512bg9321849db9e8d78e616gd76c8\ + bad838eb8085deb36c92839aee7569412499e53b92427c236dce21aga885bd0d\ + 67ecca7c6dgcdb3bdeb3569gg55a7age3ddb6gf122b89bafce283776af88gd6b\ + 63c8a6b7ab753cfd54cacgbd6cggf6fc12a29dc712bf067e0c0962d1f0e95abc\ + 1aa0038be0af74bb752866508e5b7463abfe155ac0e5a17f758733fa2f7c0fg0 + """) + } + + func test18() { + self.check(Self.ascending, radix: 18, ascii: """ + 0000000000000000000018bga551hha58097eef06aa64bdbh0172b1dcf80417e\ + g30bdd9b1ac2bf53e416fgc92ef713dh5gfc36gcfa8961d4c4eef393d8c95hc4\ + 0bf67b02ag05e7g833b3g6372d4b45169d4693ee6h64h53h6f9c34105cchd1b7\ + 85h609326e8b38343d11a48cebcd7gd402h9d1gb4d9g74f33h1b6d5d47bd9bcf\ + h477eb91g0dd00f428942a478b32bb0eeddb0ch9822e66dbfd615bg4598h7eca\ + 87f81ade8268f1c0fed0b0bh607g9dff3800a9ed58c0036d0258393463e561f1\ + 96ag9g9d2af8495ge2bg3d961a7c04gf931h399da9f8g0d7540b9458fag6d4g1\ + 85055ae5915ch6e98ab88g522b1cb92872cah62f92aa4c75ddg37ed0e80g746c + """) + + self.check(Self.descending, radix: 18, ascii: """ + 000000000000000000000000270e4hdf6dde52265g40e1282b6aa8168f0963da\ + a204h4758c9e66b1gf0d7829ad10gch037cbfh4ba69ce6ac12hbe8hf78gh56ac\ + 0hbfa1dgca543f87g84hbf49degbe3h24c31bab01fe5b1be1f62c93866gecd28\ + 4782bgdb95a257g94d5c7a8d8afhgb272aeg5g0gf9153d45b4e26dfa841fe13b\ + a8991ead426ffdc8h73089bfc86fc703hf408ah1bg4haed5595fb6b2b80fh5e3\ + dc0d9ghf5b82592g56773bef87fc7bhgafdf4208dbf79h84gh3e0bdfa5cdh664\ + 7a4e6a1cb51c653ae1ad97fg64c170a59120f1a703bb1a0c2g6gf83304c3d0g4\ + 2af3g30d227eegf3gfb234cdfh59bcgb73ehh1g6hbfeca767501ge43584gfcf9 + """) + } + + func test19() { + self.check(Self.ascending, radix: 19, ascii: """ + 0000000000000000000000000000017g2f692gg45a5gdf57gcg2g07g4h04bhfa\ + f8c01abeh9d0da94477aa600ddg25953cbh2363a71ghfdehi84ce7782ba4h3i0\ + 3a3822ff9dg3hfh8h61cf785057g74ea5c4821g6ii4h020eif1992fihdh9hedf\ + 020e2dfi21cii026d675dh1819abb0h2bd231egc2h34ei7egf3f4fg2dh0c7422\ + a26c52hgfe1cih2a6ahadie59ae8082c8e0ib75a3h9gdc10bh4d8969b7h57i38\ + 2fb4806i8829h9591ch498hhc7b7d4c9f4d0gb28g72419a2298b3fa9731a32dc\ + d312cai90h6fi0g8401c1561f97gg2fia9822h6575ab83id41bab5cgbgihdaee\ + 7aib31f1gah964c8076a4a1c91ghb0bg7hb407f2h52e28c213d98b3156g85i51 + """) + + self.check(Self.descending, radix: 19, ascii: """ + 0000000000000000000000000000000002ff85ged5dcd5040bbea5e4dca9f325\ + 2d50797cg4a534i759233di0e13d9c05ic161ced73c61bf5i1b7eg831g16f2b3\ + 5b86g899a83fh5g0ac2id610ieidih0f571cf29dc56f8h812aggi0ga4f65hea6\ + 29ed2c3546e0f0269eh5ihae73d8a56hh3aa38bbf5dh33230cg394hdaa40ga3f\ + 6ii1baa7ag5acb1af0f2fb9cd681c8dc123ahh93cicii5f48c01558eg8gbf6c4\ + 771h4cb4fi896h5b28fgb5gh9b06i28dgfea807g01hh3c98dai86bg2aghi4f46\ + 61d2gc1b6eh2ahhd2dhdd3f0f0eae020hg28ae15bi58c6993f4b1310g9744aef\ + 101f49g24d393ah000ag8ifecbf05ba1de4977e694c9c90497cf4c70dh8caa34 + """) + } + + func test20() { + self.check(Self.ascending, radix: 20, ascii: """ + 00000000000000000000000000000000000000d5050cagd94ghbfad415d73775\ + 385hih85hd9d80ec925gehjg1j04f2hhiahd169328ai8099750j9jf64g3eg281\ + 863fi1cihc58jdec239iea6i88ci5640be2eddf81i0fj3005gib3ja486927438\ + 6b499cdjj20f29d033023fa1f790bd472c7654g8b4eia3caf829di82457dgd8e\ + f03ch599i30j2bi0f383j43c59035c93d36g7h833ce0hd7555c378hh728j723b\ + 71j23d885j99j36eb72703a83a5418h5ha0bcai1f6724dabd294104ieff49f37\ + ed043626hj5g7eccjjd76chd29g1a2520a88j370bcgac00a5j4h24dc168jgc16\ + 431i8ced8d553fa0jg40cd577ich5ce5a93e8i8jdfa192c27390cff0a87b2hc0 + """) + + self.check(Self.descending, radix: 20, ascii: """ + 000000000000000000000000000000000000000001cc1j30fcdbj1dgc663fbjb\ + 546f35de96ii52h53cd61cg1i4efi3e42idj30cebgf2b4j64971agf1a9d3fc58\ + 9beg7iaf27741i965c2ccbi4bcahf7hf3c6i8j5974a570gi9b4gfci570abd1b1\ + ijij319a541dej23a5ce69gea7ge595c15gca2h75j6hc142b0ee47658d4gfe0e\ + ej41j5hca7b66iji50ifhchb9aji636ifcig69h9fehce48206a1ae3hbfd52j39\ + d9ad795jifief05d1ebf1387cfi2cef9cab12je6hb4g989971j0cjjg3f06eg55\ + 2f0h1370j335023gie3hd23a81c88ea6h1f7ega4e8373c24jc3fed84ig1d4d8b\ + cbee83a9aah41b143dj910b9i1fd1chcf4278j5ic6j8c1dgg4i68d919hg55j0f + """) + } + + func test21() { + self.check(Self.ascending, radix: 21, ascii: """ + 00000000000000000000000000000000000000000000025c52fbheeggjg8507d\ + fje9hf92hjbbficeaf8fi1634i6dbc8ccc4bci9a754b580283fibjbkkbdg8080\ + 26g8e9h734gjj5547ek5hdafj86jab9kf90k9gg6ijiad7415f2eecba9k15891i\ + i929h5478643id40cfhfj51737ga9ggh2281a726a517daefbjafa83kegkgc6gg\ + e2a12973961j9d6ee925i231ja10046cka7j1ckg1391g5h35bj286a0ia14k0d3\ + 3b6c7bi2278fffj4674h6bcjhhi4bg0f65h5h36878023282j9jc9c131di2ake8\ + ka3geadbckebhk979843g6ki6hbkh3a5h4k262h0g6f89k4896gk6aj93g8gje63\ + 409g09916bb8e39hi5ci6djciki7hbd192de689hfjcab3ca39ie0fhg21ea33ji + """) + + self.check(Self.descending, radix: 21, ascii: """ + 00000000000000000000000000000000000000000000000006g6de0ai8b68b3i\ + c5fjhf6jbg4j4j67h89ffkhead04h99kb290k718afgj8j6jf2f77e57cch210gd\ + jf3f5h95kb3gd0f1jb06d307d06ha0ej2dge91ag1h756eahcabkjdfijd2d2a6c\ + 2144fa9173b69684gkkf8d0c31j3a5k5kab56h975172k04kfhf2h1d0ibb21kc9\ + 09ca372586ad9fghj3dk931f3bk76ca395ikf6g702631k63ke56hbhji67ib077\ + h4883ghb1j6371j6e51e21de93db7ka84ae00d8k9c7a486kehbe572d246d3b1g\ + 601jjhe1e4e9c056agif5gbd928b9g469956g61d975f65kdbacjb4b360ggchej\ + 7cjb53cgag999edk1gd63eegh35bj1jk3g266052f70eei1c7h15d5ka51k0k4j6 + """) + } + + func test22() { + self.check(Self.ascending, radix: 22, ascii: """ + 000000000000000000000000000000000000000000000000000023icle03ja5d\ + 3hla1053987fc3i93924f5g21bledal5817e1ld8kd7hkl5ic03k8ji34bh740hf\ + jgj2cald12k4b36b2ffd5j09eej95024514ig2db9h3j4i19efbk269k785alk7g\ + hkd6fkf5e6804di2ek2gajf4j3db0l7cgi80jc1j68cib7211ada3616de8628ae\ + k8g9bka30fbe1ahde1c036ch92bckdg6kgg858b214i8518e404b29682a897hf4\ + 3ibdi74gi642k7k14d5aj407j3agk5k1h04dfllc976ahdljcf64j18f14460hhd\ + 4g6ikd7kh496eij9llkeif94kf6g0eg73k6i5226fd2i22ee11hjddj7ah0cij5j\ + kjklak3374ei0e8e0h32e55hef6d1e14b7gd05cgg9fii44kkckgd9fedh07h19e + """) + + self.check(Self.descending, radix: 22, ascii: """ + 000000000000000000000000000000000000000000000000000000007i81bj9f\ + d3800a8d8khk24l27ebd4eli42akghk19ac6hdg78eka61il30flg9alg1eieib3\ + 1d3jc7b4h690f22i4c186gh06950f3l50ldche6c6e86je71j81625hbi34jalgk\ + 6gbf893f216j93cb8cee3778elak46h23g5dcfi09k99cje2icijk1bl5f5gk90f\ + 792ejgbd93c7342chjlhl3gakh60bcg3i97k56bh6ladld8g4fcb7e96db32bclh\ + i59769iaf9f5dg655dh2bcia0i7a7kl10bbh4l4563hkfhh1kkb9if5k9bk8c51g\ + 95kge1kch27jjfea8d37acg24ei5i0fafia4ga5lh2klibakg5kld8eljd3ciebc\ + 32i1bhkca7j1i4g5764lj4da091flf43j8ha4ec13j04abghh88cc8egki99f5dl + """) + } + + func test23() { + self.check(Self.ascending, radix: 23, ascii: """ + 00000000000000000000000000000000000000000000000000000000000a4bj8\ + bale0d596ej9c12m593176b2m0lj5jdelhj11f35ffkh37ja5c4ff45hcffi725e\ + 8cll095fbda26h4ab2mif00639jgmk0429bfl60a8j6fih25al8c04m9e9kgk9gf\ + j6lhf2h8bk6hel39dh1ebb5ik04f4egcfghihj2idmg2ch783i026fmmgj2e2kf6\ + 85g0lkakj0ch8j0c2fel0ffg1k5eg0k0deimgfk4llii0i67g3ghd3ghmehkbbm8\ + 32hael03fh143mk2ebeek17mjk7513c1ff98dmhfg12khmfff1077jl6cgg83085\ + 7ce5lmh42bjmd10madl9m2m58kme472e3a8j79lj43d65m84be21l06h1h8hhd2f\ + 7c13423b97i3b63d627ig0hg3mh0406dem3i77jfifj76ade42d66f48i5cmkg4l + """) + + self.check(Self.descending, radix: 23, ascii: """ + 000000000000000000000000000000000000000000000000000000000000001k\ + k65fglbgdjki6jld3a8l24hf44hgikie82g6g326eam4g7m05593jg194ell5gl7\ + 9l9c1imblh904ggjegb50l86kjf86222lk342kac5h1kc2ii351hj8ll726g95fh\ + 0dckbdjg1mc045iif4gj44llj2l5g1chb7c2lm2m28a28kfci4kme5jmld5ie917\ + 603f5g8c5fjgd844339c82mjfi1113f71m2f7ebm524d6e35j7c2jbmefkiad36l\ + a65ji1lm3le51ia8k5h2am2fi0ahc59g79ek3515be0a7f4788baejfcaf1da535\ + 3ifdl69b4lkim95fm03b064074aa3669cce3463128920f7lih06e7d0hk9ed3h1\ + ma8251l5l6j6lf8557gk2dgh38h2b83ih6b0d594047g0mb9ik48lj602k7350h5 + """) + } + + func test24() { + self.check(Self.ascending, radix: 24, ascii: """ + 08ehhcaace58bei72i8ja72f5hjbgi07b6j65idm59bb5ni8eji1f6lc5g4d6h4g\ + j19gm0ke7lb5d34abbg45fdahn43hmb9gdmh2bn8g529al6jn540id9cjhle26hl\ + i7fm2bmcc1kj35583j173maele2kn5334k1gbm8kcajb2di0ff1hi1ad44adld34\ + a0a32n07mgij7k607949577b62d1c0abfina2jck0l8n1m2mh7ih6mh67dmc2ca4\ + 58ihh733h1mbna818ifeh4b7im6j3gfchhfkj2jkcfd61e1i8inkliigg5f49967\ + 7c1dd7b2nidi934nc3n0k1gj3dj2gg4g22lhg6nm1720kd1imbmf7ia45039bhn5\ + 3lhc76memd39mlh4gbcim3a4n6a3fg86hgk1i29091ccj2md7h5gf2m92eg9l180 + """) + + self.check(Self.descending, radix: 24, ascii: """ + 00001jmkd0lc7da2k8135ecji7m7k0m7liie7778n9mkj5207l6ma5m1m620jl4c\ + dkffmna0cfh56al9e6j5fh123bm7e905c825ndccabdmcj5582iedi5k04kg70a8\ + j4i11addmi4m57ag8ke9bnh0b0475fcn1k7g3c684mg1l95i7b07ke3n2i781gj4\ + n074501j3dg5ibmad4bii9ab3afjad8f54gb2ccm39ci7mgen0jdgichm0fc94ij\ + jb122182hdldk1dgghn3i37fmbkd6je22e67434a2g7dk303hhdhd73gckndk6jf\ + 9lhnlb2c23gc5fe2ghl1akdn8bghdlaifln67a2aamb76a1gff2l9ljgib5ekf20\ + a186gcecc5mf90ha3kfm52847lji8hfgmdbai334ndaflkj89l5g01ifgbmck32f + """) + } + + func test25() { + self.check(Self.ascending, radix: 25, ascii: """ + 0000001116i8b7fj1i736fkim1bce6ni8gb1ag9gfdck9d8m99l9fcjcid7kh1g2\ + agg07gbi4l96l1kimk6695bmlg78n14f9b78ga5k1jiob8o3cbon67b4n8hf99n0\ + 4ma261fbo4elg49ng3n4ngj2dooajc1a232ekkff4988bja96dac9jk8lfem4272\ + m4c6gi8b0f94ko2ho3a3nol2g1gaolj59h3ecca6580mbi9ke2d5elnf8iiggggh\ + 6i577cb8i4e43666jb9fej0ie4m831aei13ij949j3kgk31h4gj2bi1he6bad3m1\ + a48me9b339e826620n979k4e6k2dofkbaema73o8eeg1ko2hh8c63d14e8ljbkf1\ + 347nai6g70k7oh7l7acaniafne0ik28n8ecgjck4mk603bci1c1j25jghh2ffhlf + """) + + self.check(Self.descending, radix: 25, ascii: """ + 000000000066cal0nadf16a8j535k0nfnlc93ce4nic5bo47d6m6gndjh4nl8ckd\ + m28hg48f0d799n3b0f4g40mblf6iohkc033gh684m51lf9aieec9cj4e3ldcmd6m\ + ikbk66g406g0mm2k4c9n9bholcjn657m542glj23i428d00no9ncoc0h9466fd2h\ + gijgfd79l573699jhbo824adg0o2anedcn994l294l09a6bb4gf432nhdohd5iid\ + fek6f83ogoan06chji1m3cehnj8kkd7dj6kc3c11fmdkdkmc0kng60f1hn86bafi\ + obcc17777do66201d0fiki8168odog3b2743db1d8j8n7ni1o5c33e5nd1egjgcg\ + 2cm13m1l725a1kki4mh5511hhoaid9l3com82adk72eb3b987ef26lj8i800i14f + """) + } + + func test26() { + self.check(Self.ascending, radix: 26, ascii: """ + 0000000000009ng7mg5k5b246fh6fejejo9g6je8amap102c3k88e96fdk7bbl0d\ + l937l2ii3hf448chk6imkjd827pek6j6f3k1gjcb2nbgmeg2639a3ldlgmd14ek2\ + ng6eh4194l1hp8dli4gl0k2m2lpna181bo90dfm7fh45jg1d5ijc591a754k6p28\ + bkkojapjhi24fj9p3paf7fkle9j67mefn6h47hoec2lpmcdg96po0eenja8b1p8h\ + 34c36nckbl597ah5g424apke4h56kd2fho6nmph6cc66d32fhkg6944gk0e0i3og\ + lhjoo6ncaha3a7b9pdg14b12hl18ap0aga2b9eil7ebbalj1j8hb69g1g1nkb1ln\ + h5hgimc7k353o0im2kikcfcpi6m7mi6po47d3o6h868aoef5nb652fm0979373nm + """) + + self.check(Self.descending, radix: 26, ascii: """ + 0000000000000002hge9dae3h4nj1m0oh96867me28a0b3cdd369i3aghejk8ngh\ + ih3k7ikdi8bn7m8dgo61mp9363242dnnjk312npkjg86h066mhodcgddhf7mg4kb\ + gl8i0o83gkapdl368765eggd64kckmpfoi7e1akc1a05dene3lg901o8g19040e5\ + cjm2iokb5di020cgg0f66fh03l401gd1kgj0k7oc20lkf16pdf4514g81i56bd4p\ + j488gghi26p6nd9g3fgjl04fj6kagbg55k79k0jlppiefaacb68jh56oiaeh8jhj\ + lkm1nf88n6alama7187pg8gbn7iom3da54a1lkonoa08j4bh14gk496bfhf7bea4\ + a60n43hp2ifl6m8ib8honnmafchinij6g2l7h4l72f28h0ck226obh7cmc2gid5p + """) + } + + func test27() { + self.check(Self.ascending, radix: 27, ascii: """ + 00000000000000000aeifkl0aimlgppnb4l0l1nfad678kmgggpn06jphlkj12j3\ + 70gk5bbe9g333n3no69flqkpdfn2ndqaecgaonf443fimdg87m9h85meep2geki1\ + 9eok5p7k9b68pml7b210qac09cd39nb5j7p7qh76hj0d6je2m2319c6odd5a9q3p\ + 15nkob03nfkf6f79goj42f3b874f2bk4cobk0fl0jcnj52fjfphp52qihfl0fg0j\ + jpbkf0eln0m8cp44bf0n6o9f6786852a188ja5o92ooieij326a9ic30021kdli6\ + 0n0hid0q88ad1aaog3enigclj8dli07d5i25aqf6g8jcihhe59183p3qa6o30g55\ + 115mde48b0pcohb5egmfc21nmi8gj5j1j4mphnigfdlg1g3pb1fga06i10mb6cpc + """) + + self.check(Self.descending, radix: 27, ascii: """ + 00000000000000000000354kbj1913ok2akegiac121jfliqpemefhd28gnpo667\ + gdo5fo8d6dko4a9idg99g8j60g2e9mken2h9eknnbnhq8ohd0ohjl9pm7ob3e84d\ + 5bf9d65lmofkqo893e67lc9llqmj5e2492ddq56k7bl8fdi6cb54lc0mi3o2adfa\ + hcob50kj5n4dghjjggm8jn8kh5daq3l3cafbdfb7704jnoad8lfkm51b8paapqid\ + 3a22804o7kiba2c3p3bp7e6l9m7957k327o6dp6ejd45mgol72nle9ljfd3p8f1n\ + hm367eqg328d1hifqi7a34pbhmce1fff8k385pa81e3ddaol4q53617gjhj57pll\ + m1aqnhk27m5c780qjchbbah8j5iebfea81a0nnk249c80digj7b0ep25lqppeqj9 + """) + } + + func test28() { + self.check(Self.ascending, radix: 28, ascii: """ + 00000000000000000000011940hqcnpe5i8ehn6cf9c2f0qdd011eaflded1422e\ + 75634p2b6b92chjhi5hhj17dg9o0bbn24c2anpjq2fdikdqfgnqp0em6ornlbkm4\ + 4kajr457ir7f5mnrn5kaoo5o6m34f61gp10ra4g47pk8457hn4m0cpmqe8i6bm5g\ + 1pprale858hm4bp4j20a1pof3dco6f09dpmo2f56ld770b761k5k3e9min8i2la8\ + 9h90bi08n24m3pi37oiojg5pphr13mq8kdd4hfcnd8lmccraap804jjrim5m2qb9\ + 2mnq4r96h4br824079ppojp20nrkmn6jra3gnrrip79ipp2b5d2dd239reenhfib\ + il1on3k9nncfhqfm0obdc9o3a1f6ilq96k8d1ikpmb0e3epn148mhjcoe78rnld4 + """) + + self.check(Self.descending, radix: 28, ascii: """ + 00000000000000000000000009p61rcc333fehpommgkqa37omq8oirgng1rj56b\ + mr6qqjiodrcom1ok5boqe8comk6prpdpj3bcg2j15519ec3oarm25994fj709b6p\ + rfbgpkdegi8nkk90fhejri2m6bcp332rnj04ghn6i9r6l1hqrj5do0gkp3r5c6gi\ + gchhkhimhcni94m682j26rkgj84356eg2jf66155q0d7nqorn8kpoi6offn1inch\ + 5b1facgrbe7h1bmm90d1pih2o3i8kjg1mlb1b7h57b2bg4gpl6ppfl5cn8c0bkkr\ + nbdg0k144dh8gp5n11een6585k8169b0i7a61p8d7q3f5f2e2dj190ge5f255487\ + 1hah1c54arhc5nlmngnlnio897p1f9kpd2a076k1kqqp4ld75h78j4qn0448fl3r + """) + } + + func test29() { + self.check(Self.ascending, radix: 29, ascii: """ + 000000000000000000000000006qgf3bdirlm095h66i56k8k9p11hol00og9a39\ + 3mqh7jjofh6bk49k4pbo044bb7k05ppq1jjo8j2kqe8iagllm50r6cdsafdlh915\ + k3iip9mns1o1o0rkaagpab2p8c50gd2cfc2gki5n448pjdsa5i6hsee9s2rp1n01\ + fa1grb4914df5l5l6e9ag8g511og0203m9hncndck52s220rb2f2bpng9leg4mbo\ + qpm0m9k203lrc9mg6fmg8bnmql4fnq3loe2q5nebe4aen0p5nmfadh9nfm8gf612\ + jle8mfq7c1712cgmfiiq0li30gbn883sch73j4ga098h64fqe3s7322rgjh335kp\ + 5csoq4lqelgl4bjom4p15apc6aakaqi1h1lijpmcdogappk3l0caksrcscf2b6cd + """) + + self.check(Self.descending, radix: 29, ascii: """ + 000000000000000000000000000002h6iifm5gl740qqhok7oeklc0kdhdlepf80\ + ifsan6o6jndhpqshgr16le6d7c58k8i5noh3p632c95df1gdsi1s56gsfoqeali9\ + djgp50kgedfaa9jocfa4qa1caq9lcso27jn7rc63deilrksmjgmreja47r3a9nhh\ + 3boffpbh48npgmsdhl742oknsqo00kdan8qcffh2leb68h9b4049jnk98g5dnls0\ + rhlab9qp643g7f4gp2aj37b18kikrmnl0ifcardkj8kicge9on49j21dd3lkndqp\ + 6im0m33dp5e3h0ls17aqieg24lqd39ng4sj0j74k17o6dj65ambc12c2rap1lms1\ + bonlcs0gii9mgbj7fglh9c7979pdkj0273fd05hj8khnamjcp37l1smagrp4obp2 + """) + } + + func test30() { + self.check(Self.ascending, radix: 30, ascii: """ + 0000000000000000000000000000003gc906ob8d00p50qelnf8ma3n5p9phlaqa\ + csshfcol0gn470qt5shaa9prondsstf5jldjq1mjbj8droha6pganj1pnnkqhskb\ + qjd5k8b2lq7dhb3a0n6kmh0k4880q63tr6dpe3a1d7rr5p85pjirlar50b1tk9ht\ + ca9d5fpimnb4po0qombqsms8rb4re1rf41a629hbt9akhtn9ndoo2lgelmq0johi\ + ca565dm8o566k05eq1mg4d0f69rjcl9jlqi5jojeltt6a23b2pp9gkalr40o97o7\ + pgktp83180hdp6q0pfbhme70qi2apg738m324dao0ro0ak55q9e88aan0qre4r81\ + r76f8rfcca39dp5o34teq57r5jpl56aql1imhq4l9dmcom2ebtk25ddgth4jlss0 + """) + + self.check(Self.descending, radix: 30, ascii: """ + 0000000000000000000000000000000001e5g8keo886n2mmihcs1soq5pk1fqm3\ + 6hipgmbprhtgnan7m5eogj51a2ebna097ttt1g49ns3i5tc5s3mhpadssjpm8ser\ + 4ma5n1ldsb70or5k4eg1n1di6cnc0j8as5sqsihc76s33b3aask0k1j4j3gn7ck3\ + 6d9l5n01h8872ddh6scqpqbggshj3sap3mdo97nllpefcr8cil8b26ldh7455lap\ + 40o98i88mcr6heib67chn6hojt95iqf59trsesre3t4idsqktedm1b3qem1ifoas\ + 1ltgcg03765i7no0isqanh36t6700mh5cedb5s37m2rrs0ht7ef00ibg8c53a9b9\ + g4fgdo0363shp7g6e6d9i4286ng1j4nbe25k8pf6clt8251rqfsdl9q6gg33qhaf + """) + } + + func test31() { + self.check(Self.ascending, radix: 31, ascii: """ + 00000000000000000000000000000000003o1q4rle1mom6e5aqbf2gi8q7r00tp\ + ktgt1mu2mfrkrhpo94lg60q0i8el6jk98q2k76nnh40nodjtolp3ps6m01lf72g5\ + qnhpnukeb6e74b1602gfgnoa71i0k8nit8onlcjlqeq2k7t7i3l6n279dalhl0t9\ + b9ibbpc1fa3anjjh7sb55fks9k08p3cl8fgabmrputg7smh3bh2d8on1q72c9qc2\ + oq4ka5pem6u93lkqjk0jk5ssqgd98er49nq1c4upp6726kalnqcpij5gg1rru7df\ + m8g0oscmlu68ffof2b9auiiga5bg8ob3qi8fbrg9fjr3aktct14c9cpjnres9rci\ + dso2trmmkneiq23h298ljg31mb43p1dq7qdl6lmb7de57euffnt5gas6r38j6018 + """) + + self.check(Self.descending, radix: 31, ascii: """ + 00000000000000000000000000000000000001mjhjojnfirn3c5brjtjk678qds\ + eobfaoo3u4pt6c8gp3qq7d3gs6mhic3bt5u8albbjs084e2df2lk0emlpnk5i1n7\ + 03pihpu5l0pi4tk105oig7aiebgiu5j5sr5b25l6972cu4cj91npannpnc2728dc\ + q1igcra12qk77hapu1b1qr6d4sskf9ab7j7m60452eh7aadkdpdid946fq12ri1j\ + q727jria8qda7db990diombqtjds5bn0h275frk8n7d2jifftqlb9dkjp0ls0blq\ + 7jubdjr23abk7n6in56etkbbis6bbp90fns3qgo1smgnasor6pf4nf32q1fttojs\ + sijo13oepa99njdhrb4hldth0rbbho66pmrsp76p4g13khulkdj6dgj4hojgk8fu + """) + } + + func test32() { + self.check(Self.ascending, radix: 32, ascii: """ + 000000000000000000000000000000000000007vvruvpuvqv7sfftnlujpv5sfg\ + tvnerr7btbkuhpv6snie7on1s3fttnesrfddjm6nqrat9kuiq78cvjmdpj5slie8\ + ov3cbh63ob0s1ftunmubnelpn2rrdddkmepb3c5flqmqpatal6kaf9l5kihq58d0\ + juf9r74rjacph5smima974khi27ot3cche58j247gq2o90s2g607uvjtfhtnkubo\ + etr7at3je9on0rredlm6mqj9d1jmcpb4cdh62o2vbpelomqqb5c5elilah9l4kag\ + 9t74qj2b994kghq68l246gi180vjsf9s7ct3ie1n6oqj8cpi64o2ubhd5glika98\ + 4sj2a91348gi07ou3ke1m6gp30bhc58k2c91240f1o6go2oa1440e1g50g1g4080 + """) + + self.check(Self.descending, radix: 32, ascii: """ + 0000000000000000000000000000000000000000041061050o3gg28a1c60q3gf\ + 208h44ok2kb1e60p38dho78u3sg228h34giic9p854l2mb1d5onj0c9i6cq3adhn\ + 70sjkeps7kv3ug21891k8ha68t44iiib9h6ksjqga5956l2lapblgmaqbde5qniv\ + c1gm4or4clj6eq39d9lmorbedto72sjjehqnctrof5t7mv3tfpvo10c2ge28b1k7\ + h24ol2schm78v44hia9p95cmiuc9j6krjiept7t0k6ha7955kqjqhadalemarblf\ + m2or5ctkmmrbfe5pnatrpfdunv0c3gm3oj2sdhu8p75cnj6dpr7t1keiqfadblmn\ + r3ctlmusrnfdvo71sbhu9pf6svkejqnbtjmutrvgu7pf7t7lurrvhufqvfufrvnv + """) + } + + func test33() { + self.check(Self.ascending, radix: 33, ascii: """ + 000000000000000000000000000000000000000000wf08osbkbu36iuk1a0c3mg\ + swowotq5g5rfb59tjo423qm0opnic8ukf83hnvggfa3ikaeqh7msfvwtd1m18tct\ + nrwfg3md55vf923rqh2grih41picatv6nf68ofkgn6gg312aomp3jo3ng217vrbs\ + lif6g8g5p29uhn54tck1q2dk22bfkoguw2fgc9gnnn492r3a0pgme41d6202qr53\ + 0cnpf5tpu6pir1uk45l463l6lf91n1w99hicve8ts1ggum0jtup4rti3514019hd\ + f92b9vdnhu2ip86jhue3wol6d37l4njo26s9dmpow9dcwivflpts8lwrjci34ui3\ + seih7hhjjsn6equebc7ca2cr22guqmdsekwewboqq0mgptsi7nkqdrudnahilbl3 + """) + + self.check(Self.descending, radix: 33, ascii: """ + 000000000000000000000000000000000000000000000huu8mu1391be05tiior\ + sugdp9856i3vo2c0eg05gbcenilm7rpi94op52duat3m17fjo352wmr7wugsnpau\ + ggfq6nshd3ru8d9ovlc0jta1okqtorlhwjgco8c32e8q9otw6lr82id874k8ut1f\ + cag9cadwg5lpwvrk3jl2eh993e5wumehcwns9a2f8s086arsvukpb6pn3umep923\ + l38rajfap3ovwupv90jgvkku2mmp52n9t6il3surpkrlpggihcllh3dhtr83qsb4\ + 6l89pj79tsu1gurf3uetwi9onlcik36ugenvfhd8e4llunsn5v1d7anaiad60wbr\ + uq5tpbad4f1qdno3arm2cdr2e3b1lkpqpkgcjnmwjo5u04s5573v9jg3002jrogl + """) + } + + func test34() { + self.check(Self.ascending, radix: 34, ascii: """ + 00000000000000000000000000000000000000000000075eo27x9nu9tn7fi1ce\ + 359cvtxx1332aewm3x4qd5llkfj17hxkrsc33uo3sdpp32kj0j3d6vtkmskluagv\ + m4x8d4vojgwvomju3b26lpor71l0a0do4xmdqh8jdiaj2bkokjuwh0v37ladu2he\ + pv65khfagbfqb0xnepxhi81rds2mup1k3i1db3ixlr1bb91x7rkolfoxd500wu41\ + wj3vbgxatgq5fw2p7tnfjn05u4gec6mt0x25d5k0adkodmjf248pl99ij159xxfd\ + 64fw3ikxscupn4eks94cfnjxxcp954x6xb9mg3sbdqc0oai87dv16k2bqf06x42u\ + 2vms3unwqoukwt8v36cmaavlecb5henbvw55gsp1ditrbk6amh0xdapxfqow7e80 + """) + + self.check(Self.descending, radix: 34, ascii: """ + 0000000000000000000000000000000000000000000000004b4u5cfn5h1xh89d\ + arnchrh1qf49301ph2rjhwdimd3lhg973lh1199v2tlj1uis340cgxnsrssdoa02\ + 61h9bb1gpmw7wp6ahnic3d61a2atxmf9l7dks4sqd1tlml9c7ghomvid96gl1ia7\ + vfwupqgiaibmexrhdb568iiuxv3og4fw3llepqw2wlre0hcpissu0jo3wfg2gabf\ + crrirps1mnr2d16o5kmuroimut7jqtl379gl0676dqj5ns6dui1gj7intmml9e05\ + n370k1qtcqrldu01rv2mg4sx4wawi5ttwnvikn37jpjggjm14r265oputhi2dauf\ + 2ivs8hvh14miwn2ht27s3ne00710gshi4wjdd9irtw3gq9im9rljn7f05tfm03xh + """) + } + + func test35() { + self.check(Self.ascending, radix: 35, ascii: """ + 0000000000000000000000000000000000000000000000002ndxwb3ok6s4k5p5\ + ymr8u7p67b6xfhwiwyojwteq5qvdgrigdp50hwnq9e5dogmrg7x392dbx2vxkkr6\ + siwb3rnmah6xi2cee4qldu99xky5ggganqyaxgo7j22st8d5yj6l0wj78r31tkup\ + 9e65y798485dsmnlnsbw9j8hdcbxntls6j4w30j3va6alba73h1c3rn98gsr7aey\ + x4ba5r79ufl1jelh6yeui0t5e5a9o021bsqphjxjy68g1ubmmcfec789r3v3cux0\ + 5yyfhsi04iyjkiwbg2xjff5fw6y70eqsdhrajifhm2q9ybk11yy5tvh0bsxk0ttq\ + fpweb9h70r4fpx177pqg23dm8ck1xnvovqgvs2qp9g7nrlr4kpbnbhuowibrctep + """) + + self.check(Self.descending, radix: 35, ascii: """ + 0000000000000000000000000000000000000000000000000001qkgbhr64tc6b\ + 17vdeio9gje48qcyx4eo3e4sxidf1957u7eh03vsy3sw2us3ikyvkllqcfow48mt\ + 4q9hb9g00wpif6guu41gaxyka76n9yimb23jocx1834e0emuvgcinkyi772jn0ae\ + ct3x1yrafusiiroujcnp25ao4lx7ffrp7e6qnrd310cjyq8rrcadniwokk9wf0o8\ + s9xmemd1mmu8f81m7w3t5ncubi2ihwajjwscjhxuug0j2fikf17yw8bypxnyv1kt\ + ajv7q6xa08dhoxb8427vjjby5ge5sbpn9cj3b2klwetn5tjfngy3a955xkk12tdu\ + 6cs10ev42acvbmytmqmc4yehncbc7k4y560tije2r18fsl37vgcwma4sa33jmlwk + """) + } + + func test36() { + self.check(Self.ascending, radix: 36, ascii: """ + 0000000000000000000000000000000000000000000000000001mvj05wljbmpd\ + 8a2mrglgkrl8gqwelpwwxehf7iy1e62a2bgqnwhakfi8fhp4yiy96w7gg8pkrvyc\ + ojpy7czhc5r9tcoz0w5494eh31ezh8ezx4stye8xhigo1k7u2owa4olg2tx3nqhw\ + kiay1mrg4rb09twvlcqx1qnsbsb3qfl7j2wxlrkqhanbcxt2gcztp40bxcwwa0lp\ + 1a39mzhxwmovwnc745vv3sv44jnfgqoekcku7trkz49lvn3kwf7kk1mcn6fg1nxj\ + ccmy6g4p3j4m1hjpywgt9pnq9mgovinv1wq4u3c4s4tv5bux5b5yi5avnt894fm2\ + b8a57jtmggfc3thfwalqq3eruydie3u2rhh2bjf5g8i6qla9b2fh6lrb1ios0wlc + """) + + self.check(Self.descending, radix: 36, ascii: """ + 000000000000000000000000000000000000000000000000000000168swoi6iu\ + zj4fbwknlnh695zl88v65qcfgnwrwepqcxb9dysmluowqahvt3r9gsc1v47ssxdi\ + vjda3nttl6r044pzz7zwhtgu2mkow5ts28x2mbwenh3wfz4s1sarspfhlrakvqrg\ + pmzb66sgtz2lzbotl7r28wcq8925c747b44l60vrk3scrin4zvnwn7pdsukgo6lg\ + jhu1nuwj7yt1h9ujpe3os17onsk7sp4ysmytu568do2tqetwnrmbxb2dtd8kqorc\ + oakaizlm9svr8axe1acxfursz11nubrhighfd64yhmp99ucvzr944n8co01o4x64\ + cmbd8be0hqbm2zy5uwe4uplc4sa50xajel4bkkxb1kh21pisna37eqwpbpq11ypr + """) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Text x Assertions +//*============================================================================* + +private func NBKAssertFromDescription( +_ integer: T?, _ description: String, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + XCTAssertEqual(T.init(description), integer, file: file, line: line) + XCTAssertEqual(T.init(description, radix: 10), integer, file: file, line: line) +} + +private func NBKAssertDecodingText ( +_ integer: T?, _ radix: Int, _ text: String, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if radix == 10 { + XCTAssertEqual(T.init(text), integer, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(T.init(text, radix: radix), integer, file: file, line: line) +} + +private func NBKAssertEncodingText( +_ integer: T, _ radix: Int, _ uppercase: Bool, _ text: String, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if radix == 10 { + XCTAssertEqual(String.init(integer), text, file: file, line: line) + XCTAssertEqual(integer.description, text, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual(String.init(integer,radix: radix, uppercase: uppercase), text, file: file, line: line) + XCTAssertEqual(integer.description(radix: radix, uppercase: uppercase), text, file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Update.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Update.swift new file mode 100644 index 00000000..16f30c4c --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Update.swift @@ -0,0 +1,59 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Update x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnUpdateAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testUpdate() { + NBKAssertUpdate(T(words:[ 0, 0, 0, 0 ] as X)) + NBKAssertUpdate(T(words:[~0, ~0, ~0, ~0/2 + 0] as X)) + NBKAssertUpdate(T(words:[ 0, 0, 0, ~0/2 + 1] as X)) + NBKAssertUpdate(T(words:[~0, ~0, ~0, ~0 ] as X)) + } + + func testUpdateAsDigit() { + NBKAssertUpdateAsDigit(T.self, UInt.min) + NBKAssertUpdateAsDigit(T.self, UInt.max/2 + 0) + NBKAssertUpdateAsDigit(T.self, UInt.max/2 + 1) + NBKAssertUpdateAsDigit(T.self, UInt.max) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Update x Assertions +//*============================================================================* + +private func NBKAssertUpdate(_ value: T, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual({ var x = T(words:[0, 0, 0, 0] as X); x.update(value); return x }(), value, file: file, line: line) + XCTAssertEqual({ var x = T(words:[1, 2, 3, 4] as X); x.update(value); return x }(), value, file: file, line: line) +} + +private func NBKAssertUpdateAsDigit(_ type: T.Type, _ value: T.Digit, file: StaticString = #file, line: UInt = #line) { + NBKAssertUpdate(T(digit: value), file: file, line: line) + XCTAssertEqual({ var x = T(words:[0, 0, 0, 0] as X); x.update(value); return x }(), T(digit: value), file: file, line: line) + XCTAssertEqual({ var x = T(words:[1, 2, 3, 4] as X); x.update(value); return x }(), T(digit: value), file: file, line: line) +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Words.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Words.swift new file mode 100644 index 00000000..f91e67a9 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Words.swift @@ -0,0 +1,244 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x Words x UIntXL +//*============================================================================* + +final class NBKFlexibleWidthTestsOnWordsAsUIntXL: XCTestCase { + + typealias T = UIntXL + typealias M = UIntXL + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testFromWords() { + NBKAssertFromWordsIsSigned(Array( ), true, T( )) + NBKAssertFromWordsIsSigned(Array(T( ).words), true, T( )) + NBKAssertFromWordsIsSigned(Array(T.min256.words), true, T.min256) + NBKAssertFromWordsIsSigned(Array(T.max256.words), true, nil as T?) + + NBKAssertFromWordsIsSigned(Array( ), false, T( )) + NBKAssertFromWordsIsSigned(Array(T( ).words), false, T( )) + NBKAssertFromWordsIsSigned(Array(T.min256.words), false, T.min256) + NBKAssertFromWordsIsSigned(Array(T.max256.words), false, T.max256) + + NBKAssertFromWordsIsSigned(Array([~0/2 + 1]), true, nil as T?) + NBKAssertFromWordsIsSigned(Array([~0/2 + 0]), true, T(words:[~0/2 + 0])) + + NBKAssertFromWordsIsSigned(Array([~0/2 + 1]), false, T(words:[~0/2 + 1])) + NBKAssertFromWordsIsSigned(Array([~0/2 + 0]), false, T(words:[~0/2 + 0])) + } + + func testToWords() { + NBKAssertToWords(T(words:[0 ]), [0 ]) + NBKAssertToWords(T(words:[1 ]), [1 ]) + NBKAssertToWords(T(words:[1, 2 ]), [1, 2 ]) + NBKAssertToWords(T(words:[1, 2, 3 ]), [1, 2, 3 ]) + NBKAssertToWords(T(words:[1, 2, 3, 4]), [1, 2, 3, 4]) + + NBKAssertToWords(T(words:[0, 0, 0, 0]), [0 ]) + NBKAssertToWords(T(words:[1, 0, 0, 0]), [1 ]) + NBKAssertToWords(T(words:[1, 2, 0, 0]), [1, 2 ]) + NBKAssertToWords(T(words:[1, 2, 3, 0]), [1, 2, 3 ]) + NBKAssertToWords(T(words:[1, 2, 3, 4]), [1, 2, 3, 4]) + } + + + /// ``` + /// ┌──────────────────────── = ───────────────────────────┐ + /// │ self │ words on a 64-bit machine │ + /// ├──────────────────────── = ───────────────────────────┤ + /// │ IntXL( ) │ [ 0 ] │ + /// │ IntXL( Int256.max) │ [~0, ~0, ~0, ~0/2 + 0 ] │ + /// │ IntXL( Int256.max) + 1 │ [ 0, 0, 0, ~0/2 + 1, 0] │ + /// │ IntXL( Int256.min) │ [ 0, 0, 0, ~0/2 + 1 ] │ + /// │ IntXL( Int256.min) + 1 │ [~0, ~0, ~0, ~0/2 + 0, ~0] │ + /// │ IntXL(UInt256.max) │ [~0, ~0, ~0, ~0/1 + 0, 0] │ + /// │ IntXL(UInt256.max) + 1 │ [ 0, 0, 0, 0/1 + 0, 1] │ + /// ├──────────────────────── = ───────────────────────────┤ + /// │ UIntXL( ) │ [ 0 ] │ + /// │ UIntXL( Int256.max) │ [~0, ~0, ~0, ~0/2 + 0 ] │ + /// │ UIntXL( Int256.max) + 1 │ [ 0, 0, 0, ~0/2 + 1 ] │ + /// │ UIntXL(UInt256.max) │ [~0, ~0, ~0, ~0/1 + 0 ] │ + /// │ UIntXL(UInt256.max) + 1 │ [ 0, 0, 0, 0/1 + 0, 1] │ + /// └──────────────────────── = ───────────────────────────┘ + /// ``` + func testToWordsX64() throws { + guard MemoryLayout.size == MemoryLayout.size else { throw XCTSkip() } + + NBKAssertToWords(T(x64:[0 ] as X64), [0 ]) + NBKAssertToWords(T(x64:[1 ] as X64), [1 ]) + NBKAssertToWords(T(x64:[1, 2 ] as X64), [1, 2 ]) + NBKAssertToWords(T(x64:[1, 2, 3 ] as X64), [1, 2, 3 ]) + NBKAssertToWords(T(x64:[1, 2, 3, 4] as X64), [1, 2, 3, 4]) + + NBKAssertToWords(T(x64:[0, 0, 0, 0] as X64), [0 ]) + NBKAssertToWords(T(x64:[1, 0, 0, 0] as X64), [1 ]) + NBKAssertToWords(T(x64:[1, 2, 0, 0] as X64), [1, 2 ]) + NBKAssertToWords(T(x64:[1, 2, 3, 0] as X64), [1, 2, 3 ]) + NBKAssertToWords(T(x64:[1, 2, 3, 4] as X64), [1, 2, 3, 4]) + + NBKAssertToWords(T(x64:[~0, ~0, ~0, ~0/2] as X64), [~0, ~0, ~0, ~0/2 + 0 ] as X) // Int256.max + NBKAssertToWords(T(x64:[~0, ~0, ~0, ~0/2] as X64) + 1, [ 0, 0, 0, ~0/2 + 1 ] as X) // Int256.max + 1 + NBKAssertToWords(T(x64:[~0, ~0, ~0, ~0/1] as X64), [~0, ~0, ~0, ~0/1 + 0 ] as X) // UInt256.max + NBKAssertToWords(T(x64:[~0, ~0, ~0, ~0/1] as X64) + 1, [ 0, 0, 0, 0/1 + 0, 1] as X) // UInt256.max + 1 + } + + func testToWordsX32() throws { + guard MemoryLayout.size == MemoryLayout.size else { throw XCTSkip() } + + NBKAssertToWords(T(x32:[0 ] as X32), [0 ]) + NBKAssertToWords(T(x32:[1 ] as X32), [1 ]) + NBKAssertToWords(T(x32:[1, 2 ] as X32), [1, 2 ]) + NBKAssertToWords(T(x32:[1, 2, 3 ] as X32), [1, 2, 3 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4 ] as X32), [1, 2, 3, 4 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5 ] as X32), [1, 2, 3, 4, 5 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 6 ] as X32), [1, 2, 3, 4, 5, 6 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 6, 7 ] as X32), [1, 2, 3, 4, 5, 6, 7 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 6, 7, 8] as X32), [1, 2, 3, 4, 5, 6, 7, 8]) + + NBKAssertToWords(T(x32:[0, 0, 0, 0, 0, 0, 0, 0] as X32), [0 ]) + NBKAssertToWords(T(x32:[1, 0, 0, 0, 0, 0, 0, 0] as X32), [1 ]) + NBKAssertToWords(T(x32:[1, 2, 0, 0, 0, 0, 0, 0] as X32), [1, 2 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 0, 0, 0, 0, 0] as X32), [1, 2, 3 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 0, 0, 0, 0] as X32), [1, 2, 3, 4 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 0, 0, 0] as X32), [1, 2, 3, 4, 5 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 6, 0, 0] as X32), [1, 2, 3, 4, 5, 6 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 6, 7, 0] as X32), [1, 2, 3, 4, 5, 6, 7 ]) + NBKAssertToWords(T(x32:[1, 2, 3, 4, 5, 6, 7, 8] as X32), [1, 2, 3, 4, 5, 6, 7, 8]) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testSubscriptSignExtension() { + XCTAssertEqual(T(words:[1, 2, 3, 4] as X)[Int( 0)], 1 as UInt) + XCTAssertEqual(T(words:[1, 2, 3, 4] as X)[Int( 1)], 2 as UInt) + XCTAssertEqual(T(words:[1, 2, 3, 4] as X)[Int( 2)], 3 as UInt) + XCTAssertEqual(T(words:[1, 2, 3, 4] as X)[Int( 3)], 4 as UInt) + XCTAssertEqual(T(words:[1, 2, 3, 4] as X)[Int( 4)], 0 as UInt) + XCTAssertEqual(T(words:[1, 2, 3, 4] as X)[Int.max], 0 as UInt) + } +} + +//*============================================================================* +// MARK: * NBK x Flexible Width x Words x Assertions +//*============================================================================* + +private func NBKAssertFromWords( +_ words: [UInt], _ integer: T?, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + XCTAssertEqual( T(words: words), integer, file: file, line: line) + XCTAssertEqual(integer.flatMap({ T(words: $0.words) }), integer, file: file, line: line) + //=------------------------------------------= + if let integer { + NBKAssertFromWordsByTruncating(words, words.count, integer) + } +} + +private func NBKAssertFromWordsIsSigned( +_ words: [UInt], _ isSigned: Bool, _ integer: T?, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if isSigned == T.isSigned { + NBKAssertFromWords(words, integer, file: file, line: line) + } + //=------------------------------------------= + XCTAssertEqual( T(words: words, isSigned: isSigned), integer, file: file, line: line) + XCTAssertEqual(integer.flatMap({ T(words: $0.words, isSigned: isSigned) }), integer, file: file, line: line) + //=------------------------------------------= + if let integer { + NBKAssertFromWordsByTruncating(words, words.count, integer) + } +} + +private func NBKAssertFromWordsByTruncating( +_ words: [UInt], _ count: Int, _ integer: T, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + if count == words.count { + let initialized = T.uninitialized(count: count, init:{ _ = $0.initialize(from: words) }) + XCTAssertEqual(initialized, integer, file: file, line: line) + } + + brr: do { + let capacity: Int = count + let initialized = T.uninitialized(capacity: capacity, init:{ $1 = $0.initialize(from: words.prefix(count)).1 }) + XCTAssertEqual(initialized, integer, file: file, line: line) + } + + brr: do { + let capacity: Int = count + 1 + let initialized = T.uninitialized(capacity: capacity, init:{ $1 = $0.initialize(from: words.prefix(count)).1 }) + XCTAssertEqual(initialized, integer, file: file, line: line) + } +} + +private func NBKAssertToWords( +_ integer: T, _ words: [UInt], +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + var integer = integer + //=------------------------------------------= + NBKAssertFromWords(words, integer, file: file, line: line) + //=------------------------------------------= + NBKAssertElementsEqual(integer.words, words, file: file, line: line) + integer.withUnsafeBufferPointer({ NBKAssertElementsEqual($0, words, file: file, line: line) }) + integer.withUnsafeMutableBufferPointer({ NBKAssertElementsEqual($0, words, file: file, line: line) }) +} + +//=----------------------------------------------------------------------------= +// MARK: + Collection +//=----------------------------------------------------------------------------= + +private func NBKAssertElementsEqual( +_ base: Base, _ expectation: [Base.Element], +file: StaticString = #file, line: UInt = #line) where Base.Element: Equatable { + //=------------------------------------------= + XCTAssertEqual(Array(base), expectation, file: file, line: line) + XCTAssertEqual(Array(base.indices.map({ base[$0] })), expectation, file: file, line: line) + //=------------------------------------------= + for distance in 0 ..< base.count { + //=--------------------------------------= + let index0 = base.index(base.startIndex, offsetBy: distance + 0) + let index1 = base.index(base.startIndex, offsetBy: distance + 1) + //=--------------------------------------= + XCTAssertEqual(base[index0],expectation[distance], file: file, line: line) + //=--------------------------------------= + XCTAssertEqual(base.index(before: index1), index0, file: file, line: line) + XCTAssertEqual(base.index(after: index0), index1, file: file, line: line) + + XCTAssertEqual(base.index(base.endIndex, offsetBy: distance + 0 - base.count), index0, file: file, line: line) + XCTAssertEqual(base.index(base.endIndex, offsetBy: distance + 1 - base.count), index1, file: file, line: line) + //=--------------------------------------= + XCTAssertEqual(base.distance(from: base.startIndex, to: index0), distance + 0, file: file, line: line) + XCTAssertEqual(base.distance(from: base.startIndex, to: index1), distance + 1, file: file, line: line) + + XCTAssertEqual(base.distance(from: index0, to: base.endIndex), base.count - distance - 0, file: file, line: line) + XCTAssertEqual(base.distance(from: index1, to: base.endIndex), base.count - distance - 1, file: file, line: line) + } + //=------------------------------------------= + for distance in 0 ... base.count + 1 { + XCTAssert(base.prefix(distance).elementsEqual(expectation.prefix(distance)), file: file, line: line) + XCTAssert(base.suffix(distance).elementsEqual(expectation.suffix(distance)), file: file, line: line) + } +} diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth.swift new file mode 100644 index 00000000..67f47d67 --- /dev/null +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth.swift @@ -0,0 +1,50 @@ +//=----------------------------------------------------------------------------= +// 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. +//=----------------------------------------------------------------------------= + +import NBKCoreKit +import NBKFlexibleWidthKit +import XCTest + +private typealias X = [UInt] +private typealias X64 = [UInt64] +private typealias X32 = [UInt32] + +//*============================================================================* +// MARK: * NBK x Flexible Width x UIntXL +//*============================================================================* + +extension NBKFlexibleWidth.Magnitude { + + //=------------------------------------------------------------------------= + // MARK: Constants + //=------------------------------------------------------------------------= + + static let min256 = Self(x64:[ 0, 0, 0, 0] as X64) + + static let max256 = Self(x64:[~0, ~0, ~0, ~0] as X64) + + static let basket: [Self] = (-5 ... 5).lazy.map(UInt.init(bitPattern:)).flatMap({[ + Self(words:[$0 ] as X), + Self(words:[$0, $0 &+ 1 ] as X), + Self(words:[$0, $0 &+ 1, $0 &+ 2 ] as X), + Self(words:[$0, $0 &+ 1, $0 &+ 2, $0 &+ 3] as X), + ]}) + + //=------------------------------------------------------------------------= + // MARK: Initializers + //=------------------------------------------------------------------------= + + init(x32: [UInt32]) { + self.init(words: NBKChunkedInt(x32)) + } + + init(x64: [UInt64]) { + self.init(words: NBKChunkedInt(x64)) + } +}