From 759f2e532f1b651842d0010ea9f3e2fcd8c7a4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Bystr=C3=B6m=20Ericsson?= Date: Fri, 15 Sep 2023 14:02:52 +0200 Subject: [PATCH] [NBKSignedKit] Tests (#81). --- .../NBKSignedKit/NBKSigned+Comparisons.swift | 17 +- .../NBKFlexibleWidth+Division.swift | 2 - .../NBKSigned+Addition.swift | 12 +- .../NBKSigned+Comparisons.swift | 173 ++++++++++++++++++ .../NBKSigned+Division.swift | 140 ++++++++++++++ .../NBKSigned+Multiplication.swift | 98 ++++++++++ .../NBKSigned+Subtract.swift | 10 +- 7 files changed, 433 insertions(+), 19 deletions(-) create mode 100644 Tests/NBKSignedKitTests/NBKSigned+Comparisons.swift create mode 100644 Tests/NBKSignedKitTests/NBKSigned+Division.swift create mode 100644 Tests/NBKSignedKitTests/NBKSigned+Multiplication.swift diff --git a/Sources/NBKSignedKit/NBKSigned+Comparisons.swift b/Sources/NBKSignedKit/NBKSigned+Comparisons.swift index 25162311..7d1b5bd4 100644 --- a/Sources/NBKSignedKit/NBKSigned+Comparisons.swift +++ b/Sources/NBKSignedKit/NBKSigned+Comparisons.swift @@ -19,11 +19,6 @@ extension NBKSigned { // MARK: Accessors //=------------------------------------------------------------------------= - /// Returns `1` if this value is positive, `-1` if it is negative, and `0` otherwise. - @inlinable public func signum() -> Int { - self.isZero ? 0 : self.sign == Sign.plus ? 1 : -1 - } - /// Returns whether this value is equal to zero. @inlinable public var isZero: Bool { self.magnitude.isZero @@ -39,6 +34,16 @@ extension NBKSigned { self.sign == Sign.plus && !self.isZero } + /// Returns whether this value is a power of two. + @inlinable public var isPowerOf2: Bool { + self.sign == Sign.plus && self.magnitude.isPowerOf2 + } + + /// Returns `1` if this value is positive, `-1` if it is negative, and `0` otherwise. + @inlinable public func signum() -> Int { + self.isZero ? 0 : self.sign == Sign.plus ? 1 : -1 + } + //=------------------------------------------------------------------------= // MARK: Utilities //=------------------------------------------------------------------------= @@ -77,7 +82,7 @@ extension NBKSigned { } } - @inlinable public func compared(to other: Digit) -> Int { + @_disfavoredOverload @inlinable public func compared(to other: Digit) -> Int { if self.sign != other.sign { return self.isZero && other.isZero ? 0 : self.sign == Sign.plus ? 1 : -1 } else { diff --git a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift index 84645c5f..e378a2f4 100644 --- a/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift +++ b/Tests/NBKFlexibleWidthKitTests/NBKFlexibleWidth+Division.swift @@ -68,7 +68,6 @@ final class NBKFlexibleWidthTestsOnDivisionAsIntXL: XCTestCase { NBKAssertDivision(T(words:[1, 2, 3, 4 + 1 << 63] as W), T(words:[ 2, 3, 4, 5 &+ 1 << 63] as W), T(1), -T(words:[1, 1, 1, 1] as W)) NBKAssertDivision(T(words:[1, 2, 3, 4 + 1 << 63] as W), T(words:[ 3, 4, 5, 6 &+ 1 << 63] as W), T(1), -T(words:[2, 2, 2, 2] as W)) NBKAssertDivision(T(words:[1, 2, 3, 4 + 1 << 63] as W), T(words:[ 4, 5, 6, 7 &+ 1 << 63] as W), T(1), -T(words:[3, 3, 3, 3] as W)) - NBKAssertDivision(T(words:[1, 2, 3, 4 + 1 << 63] as W), T(words:[~0, ~2, ~3, ~4 &+ 1 << 63] as W), -T(1), -T(words:[0, 0, 0, 0] as W)) NBKAssertDivision(T(words:[1, 2, 3, 4 + 1 << 63] as W), T(words:[~1, ~3, ~4, ~5 &+ 1 << 63] as W), -T(1), -T(words:[1, 1, 1, 1] as W)) NBKAssertDivision(T(words:[1, 2, 3, 4 + 1 << 63] as W), T(words:[~2, ~4, ~5, ~6 &+ 1 << 63] as W), -T(1), -T(words:[2, 2, 2, 2] as W)) @@ -190,7 +189,6 @@ final class NBKFlexibleWidthTestsOnDivisionAsUIntXL: XCTestCase { NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X), T(x64:[ 0, 1, 2, 3 &+ 1 << 63] as X), T(1), T(x64:[1, 1, 1, 1] as X)) NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X), T(x64:[~0, ~0, 0, 2 &+ 1 << 63] as X), T(1), T(x64:[2, 2, 2, 2] as X)) NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X), T(x64:[~1, ~1, ~0, 0 &+ 1 << 63] as X), T(1), T(x64:[3, 3, 3, 3] as X)) - NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X), T(x64:[~2, ~2, ~1, ~0 &+ 1 << 63] as X), T(1), T(x64:[4, 4, 4, 4] as X)) NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X), T(x64:[~3, ~3, ~2, ~1 &+ 1 << 63] as X), T(1), T(x64:[5, 5, 5, 5] as X)) NBKAssertDivision(T(x64:[1, 2, 3, 4 + 1 << 63] as X), T(x64:[~4, ~4, ~3, ~2 &+ 1 << 63] as X), T(1), T(x64:[6, 6, 6, 6] as X)) diff --git a/Tests/NBKSignedKitTests/NBKSigned+Addition.swift b/Tests/NBKSignedKitTests/NBKSigned+Addition.swift index 665d82c8..dcff0959 100644 --- a/Tests/NBKSignedKitTests/NBKSigned+Addition.swift +++ b/Tests/NBKSignedKitTests/NBKSigned+Addition.swift @@ -33,12 +33,12 @@ final class NBKSignedTestsOnAdditionAsSIntXL: XCTestCase { // MARK: Tests //=------------------------------------------------------------------------= - func testAdding() { + func testAddingLargeToLarge() { NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[3, 0, 0, 0] as X)), T(M(x64:[ 2, 0, 0, 1] as X))) NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[0, 3, 0, 0] as X)), T(M(x64:[~0, 2, 0, 1] as X))) NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[0, 0, 3, 0] as X)), T(M(x64:[~0, ~0, 2, 1] as X))) NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[0, 0, 0, 3] as X)), T(M(x64:[~0, ~0, ~0, 3] as X))) - + NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), -T(M(x64:[3, 0, 0, 0] as X)), T(M(x64:[~3, ~0, ~0, 0] as X))) NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), -T(M(x64:[0, 3, 0, 0] as X)), T(M(x64:[~0, ~3, ~0, 0] as X))) NBKAssertAddition( T(M(x64:[~0, ~0, ~0, 0] as X)), -T(M(x64:[0, 0, 3, 0] as X)), T(M(x64:[~0, ~0, ~3, 0] as X))) @@ -56,10 +56,10 @@ final class NBKSignedTestsOnAdditionAsSIntXL: XCTestCase { } //=------------------------------------------------------------------------= - // MARK: Tests x Digit + // MARK: Tests x Digit (and Self) //=------------------------------------------------------------------------= - func testAddingDigit() { + func testAddingSmallToSmall() { NBKAssertAdditionByDigit( T(M(1)), D(U(2)), T(M(3))) NBKAssertAdditionByDigit( T(M(1)), D(U(1)), T(M(2))) NBKAssertAdditionByDigit( T(M(1)), D(U(0)), T(M(1))) @@ -116,11 +116,11 @@ file: StaticString = #file, line: UInt = #line) { private func NBKAssertAdditionByDigit( _ lhs: NBKSigned, _ rhs: NBKSigned.Digit, _ partialValue: NBKSigned, file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + NBKAssertAddition(lhs, NBKSigned(digit: rhs), partialValue) //=------------------------------------------= NBKAssertIdentical( lhs + rhs, partialValue, file: file, line: line) NBKAssertIdentical({ var lhs = lhs; lhs += rhs; return lhs }(), partialValue, file: file, line: line) - //=------------------------------------------= - NBKAssertAddition(lhs, NBKSigned(digit: rhs), partialValue) } #endif diff --git a/Tests/NBKSignedKitTests/NBKSigned+Comparisons.swift b/Tests/NBKSignedKitTests/NBKSigned+Comparisons.swift new file mode 100644 index 00000000..0590c2d5 --- /dev/null +++ b/Tests/NBKSignedKitTests/NBKSigned+Comparisons.swift @@ -0,0 +1,173 @@ +//=----------------------------------------------------------------------------= +// 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 NBKSignedKit +import XCTest + +private typealias W = [UInt] +private typealias X = [UInt64] +private typealias Y = [UInt32] + +//*============================================================================* +// MARK: * NBK x Signed x Comparisons +//*============================================================================* + +final class NBKSignedTestsOnComparisonsAsSIntXL: XCTestCase { + + typealias T = NBKSigned + typealias M = NBKSigned.Magnitude + typealias D = NBKSigned.Digit + typealias U = NBKSigned.Digit.Magnitude + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testIsZero() { + XCTAssertTrue (( T(0)).isZero) + XCTAssertTrue ((-T(0)).isZero) + XCTAssertFalse(( T(1)).isZero) + XCTAssertFalse((-T(1)).isZero) + } + + func testIsLessThanZero() { + XCTAssertFalse(( T(0)).isLessThanZero) + XCTAssertFalse((-T(0)).isLessThanZero) + XCTAssertFalse(( T(1)).isLessThanZero) + XCTAssertTrue ((-T(1)).isLessThanZero) + } + + func testIsMoreThanZero() { + XCTAssertFalse(( T(0)).isMoreThanZero) + XCTAssertFalse((-T(0)).isMoreThanZero) + XCTAssertTrue (( T(1)).isMoreThanZero) + XCTAssertFalse((-T(1)).isMoreThanZero) + } + + func testSignum() { + NBKAssertSignum(( T(0)), Int( 0)) + NBKAssertSignum((-T(0)), Int( 0)) + NBKAssertSignum(( T(1)), Int( 1)) + NBKAssertSignum((-T(1)), Int(-1)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testHashing() { + var union = Set() + union.insert( T(0)) + union.insert( T(0)) + union.insert(-T(0)) + union.insert(-T(0)) + union.insert( T(1)) + union.insert( T(1)) + union.insert(-T(1)) + union.insert(-T(1)) + XCTAssertEqual(union.count, 3) + } + + func testComparingLargeWithLarge() { + NBKAssertComparisons(T(M(words:[0, 2, 3, 4] as W)), T(M(words:[1, 2, 3, 4] as W)), -Int(1)) + NBKAssertComparisons(T(M(words:[1, 0, 3, 4] as W)), T(M(words:[1, 2, 3, 4] as W)), -Int(1)) + NBKAssertComparisons(T(M(words:[1, 2, 0, 4] as W)), T(M(words:[1, 2, 3, 4] as W)), -Int(1)) + NBKAssertComparisons(T(M(words:[1, 2, 3, 0] as W)), T(M(words:[1, 2, 3, 4] as W)), -Int(1)) + NBKAssertComparisons(T(M(words:[0, 2, 3, 4] as W)), T(M(words:[0, 2, 3, 4] as W)), Int(0)) + NBKAssertComparisons(T(M(words:[1, 0, 3, 4] as W)), T(M(words:[1, 0, 3, 4] as W)), Int(0)) + NBKAssertComparisons(T(M(words:[1, 2, 0, 4] as W)), T(M(words:[1, 2, 0, 4] as W)), Int(0)) + NBKAssertComparisons(T(M(words:[1, 2, 3, 0] as W)), T(M(words:[1, 2, 3, 0] as W)), Int(0)) + NBKAssertComparisons(T(M(words:[1, 2, 3, 4] as W)), T(M(words:[0, 2, 3, 4] as W)), Int(1)) + NBKAssertComparisons(T(M(words:[1, 2, 3, 4] as W)), T(M(words:[1, 0, 3, 4] as W)), Int(1)) + NBKAssertComparisons(T(M(words:[1, 2, 3, 4] as W)), T(M(words:[1, 2, 0, 4] as W)), Int(1)) + NBKAssertComparisons(T(M(words:[1, 2, 3, 4] as W)), T(M(words:[1, 2, 3, 0] as W)), Int(1)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit (and Self) + //=------------------------------------------------------------------------= + + func testComparingSmallWithSmall() { + NBKAssertComparisonsByDigit( T(0), D(0), Int(0)) + NBKAssertComparisonsByDigit( T(0), -D(0), Int(0)) + NBKAssertComparisonsByDigit(-T(0), D(0), Int(0)) + NBKAssertComparisonsByDigit(-T(0), -D(0), Int(0)) + + NBKAssertComparisonsByDigit( T(1), D(1), Int(0)) + NBKAssertComparisonsByDigit( T(1), -D(1), Int(1)) + NBKAssertComparisonsByDigit(-T(1), D(1), -Int(1)) + NBKAssertComparisonsByDigit(-T(1), -D(1), Int(0)) + + NBKAssertComparisonsByDigit( T(2), D(3), -Int(1)) + NBKAssertComparisonsByDigit( T(2), -D(3), Int(1)) + NBKAssertComparisonsByDigit(-T(2), D(3), -Int(1)) + NBKAssertComparisonsByDigit(-T(2), -D(3), Int(1)) + + NBKAssertComparisonsByDigit( T(3), D(2), Int(1)) + NBKAssertComparisonsByDigit( T(3), -D(2), Int(1)) + NBKAssertComparisonsByDigit(-T(3), D(2), -Int(1)) + NBKAssertComparisonsByDigit(-T(3), -D(2), -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)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Signed x Comparisons x Assertions +//*============================================================================* + +private func NBKAssertSignum( +_ operand: NBKSigned, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(Int(operand.signum() as Int), signum, file: file, line: line) +} + +private func NBKAssertComparisons( +_ lhs: NBKSigned, _ rhs: NBKSigned, _ 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 NBKAssertComparisonsByDigit( +_ lhs: NBKSigned, _ rhs: NBKSigned.Digit, _ signum: Int, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + NBKAssertComparisons(lhs, NBKSigned(digit: rhs), signum) + //=------------------------------------------= + XCTAssertEqual(lhs.compared(to: rhs), signum, file: file, line: line) +} + +#endif diff --git a/Tests/NBKSignedKitTests/NBKSigned+Division.swift b/Tests/NBKSignedKitTests/NBKSigned+Division.swift new file mode 100644 index 00000000..59369925 --- /dev/null +++ b/Tests/NBKSignedKitTests/NBKSigned+Division.swift @@ -0,0 +1,140 @@ +//=----------------------------------------------------------------------------= +// 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 NBKSignedKit +import XCTest + +private typealias W = [UInt] +private typealias X = [UInt64] +private typealias Y = [UInt32] + +//*============================================================================* +// MARK: * NBK x Signed x Division x SIntXL +//*============================================================================* + +final class NBKSignedTestsOnDivisionAsSIntXL: XCTestCase { + + typealias T = NBKSigned + typealias M = NBKSigned.Magnitude + typealias D = NBKSigned.Digit + typealias U = NBKSigned.Digit.Magnitude + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testDividingLargeByLarge() { + NBKAssertDivision( T(M(x64:[~2, ~4, ~6, 9] as X)), T(M(x64:[~1, ~2, ~3, 4] as X)), T(2), T(1)) + NBKAssertDivision( T(M(x64:[~3, ~6, ~9, 14] as X)), -T(M(x64:[~1, ~2, ~3, 4] as X)), -T(3), T(2)) + NBKAssertDivision(-T(M(x64:[~4, ~8, ~12, 19] as X)), T(M(x64:[~1, ~2, ~3, 4] as X)), -T(4), -T(3)) + NBKAssertDivision(-T(M(x64:[~5, ~10, ~15, 24] as X)), -T(M(x64:[~1, ~2, ~3, 4] as X)), T(5), -T(4)) + } + + func testDividingLargeByLargeWithLargeRemainder() { + NBKAssertDivision( T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), T(M(x64:[ 1, 2, 3, 4 &+ 1 << 63] as X)), T(1), T(M(x64:[0, 0, 0, 0] as X))) + NBKAssertDivision( T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), T(M(x64:[ 0, 1, 2, 3 &+ 1 << 63] as X)), T(1), T(M(x64:[1, 1, 1, 1] as X))) + NBKAssertDivision( T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), -T(M(x64:[~0, ~0, 0, 2 &+ 1 << 63] as X)), -T(1), T(M(x64:[2, 2, 2, 2] as X))) + NBKAssertDivision( T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), -T(M(x64:[~1, ~1, ~0, 0 &+ 1 << 63] as X)), -T(1), T(M(x64:[3, 3, 3, 3] as X))) + NBKAssertDivision(-T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), T(M(x64:[~2, ~2, ~1, ~0 &+ 1 << 63] as X)), -T(1), -T(M(x64:[4, 4, 4, 4] as X))) + NBKAssertDivision(-T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), T(M(x64:[~3, ~3, ~2, ~1 &+ 1 << 63] as X)), -T(1), -T(M(x64:[5, 5, 5, 5] as X))) + NBKAssertDivision(-T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), -T(M(x64:[~4, ~4, ~3, ~2 &+ 1 << 63] as X)), T(1), -T(M(x64:[6, 6, 6, 6] as X))) + NBKAssertDivision(-T(M(x64:[1, 2, 3, 4 + 1 << 63] as X)), -T(M(x64:[~5, ~5, ~4, ~3 &+ 1 << 63] as X)), T(1), -T(M(x64:[7, 7, 7, 7] as X))) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit + //=------------------------------------------------------------------------= + + func testDividingSmallBySmall() { + NBKAssertDivisionByDigit( T( ), D(1), T( ), D( )) + NBKAssertDivisionByDigit( T( ), -D(2), -T( ), D( )) + NBKAssertDivisionByDigit(-T(7), D(1), -T(7), -D( )) + NBKAssertDivisionByDigit(-T(7), -D(2), T(3), -D(1)) + + NBKAssertDivisionByDigit( T(7), D(3), T(2), D(1)) + NBKAssertDivisionByDigit( T(7), -D(3), -T(2), D(1)) + NBKAssertDivisionByDigit(-T(7), D(3), -T(2), -D(1)) + NBKAssertDivisionByDigit(-T(7), -D(3), T(2), -D(1)) + } + + func testDividingLargeBySmall() { + NBKAssertDivisionByDigit( T(M(words:[1, 2, 3, 4] as W)), D(2), T(M(words:[0, ~0/2 + 2, 1, 2] as W)), D(1)) + NBKAssertDivisionByDigit( T(M(words:[1, 2, 3, 4] as W)), -D(2), -T(M(words:[0, ~0/2 + 2, 1, 2] as W)), D(1)) + NBKAssertDivisionByDigit(-T(M(words:[1, 2, 3, 4] as W)), D(2), -T(M(words:[0, ~0/2 + 2, 1, 2] as W)), -D(1)) + NBKAssertDivisionByDigit(-T(M(words:[1, 2, 3, 4] as W)), -D(2), T(M(words:[0, ~0/2 + 2, 1, 2] as W)), -D(1)) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x /= 0) + XCTAssertNotNil(x %= 0) + XCTAssertNotNil(x / 0) + XCTAssertNotNil(x % 0) + XCTAssertNotNil(x.quotientAndRemainder(dividingBy: 0)) + } + } +} + +//*============================================================================* +// MARK: * NBK x Signed x Division x Assertions +//*============================================================================* + +private func NBKAssertDivision( +_ lhs: NBKSigned, _ rhs: NBKSigned, _ quotient: NBKSigned, _ remainder: NBKSigned, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + XCTAssertEqual(lhs, quotient * rhs + remainder, "dividend != divisor * quotient + remainder", file: file, line: line) + //=------------------------------------------= + if !overflow { + NBKAssertIdentical(lhs / rhs, quotient, file: file, line: line) + NBKAssertIdentical(lhs % rhs, remainder, file: file, line: line) + + NBKAssertIdentical({ var x = lhs; x /= rhs; return x }(), quotient, file: file, line: line) + NBKAssertIdentical({ var x = lhs; x %= rhs; return x }(), remainder, file: file, line: line) + + NBKAssertIdentical(lhs.quotientAndRemainder(dividingBy: rhs).quotient, quotient, file: file, line: line) + NBKAssertIdentical(lhs.quotientAndRemainder(dividingBy: rhs).remainder, remainder, file: file, line: line) + } else { + XCTFail("\(NBKSigned.self) is not a binary integer.") + } +} + +private func NBKAssertDivisionByDigit( +_ lhs: NBKSigned, _ rhs: NBKSigned.Digit, _ quotient: NBKSigned, _ remainder: NBKSigned.Digit, _ overflow: Bool = false, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + let extended = NBKSigned(digit: remainder) + //=------------------------------------------= + NBKAssertDivision(lhs, NBKSigned(digit: rhs), quotient, extended) + //=------------------------------------------= + XCTAssertEqual(lhs, quotient * rhs + remainder, "dividend != divisor * quotient + remainder", file: file, line: line) + //=------------------------------------------= + if !overflow { + NBKAssertIdentical(lhs / rhs, quotient, file: file, line: line) + NBKAssertIdentical(lhs % rhs, remainder, file: file, line: line) + + NBKAssertIdentical({ var x = lhs; x /= rhs; return x }(), quotient, file: file, line: line) + NBKAssertIdentical({ var x = lhs; x %= rhs; return x }(), extended, file: file, line: line) + + NBKAssertIdentical(lhs.quotientAndRemainder(dividingBy: rhs).quotient, quotient, file: file, line: line) + NBKAssertIdentical(lhs.quotientAndRemainder(dividingBy: rhs).remainder, remainder, file: file, line: line) + } else { + XCTFail("\(NBKSigned.self) is not a binary integer.") + } +} + +#endif diff --git a/Tests/NBKSignedKitTests/NBKSigned+Multiplication.swift b/Tests/NBKSignedKitTests/NBKSigned+Multiplication.swift new file mode 100644 index 00000000..5f25647d --- /dev/null +++ b/Tests/NBKSignedKitTests/NBKSigned+Multiplication.swift @@ -0,0 +1,98 @@ +//=----------------------------------------------------------------------------= +// 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 NBKSignedKit +import XCTest + +private typealias W = [UInt] +private typealias X = [UInt64] +private typealias Y = [UInt32] + +//*============================================================================* +// MARK: * NBK x Signed x Multiplication x SIntXL +//*============================================================================* + +final class NBKSignedTestsOnMultiplicationAsSIntXL: XCTestCase { + + typealias T = NBKSigned + typealias M = NBKSigned.Magnitude + typealias D = NBKSigned.Digit + typealias U = NBKSigned.Digit.Magnitude + + //=------------------------------------------------------------------------= + // MARK: Tests + //=------------------------------------------------------------------------= + + func testMultiplyingLargeByLarge() { + NBKAssertMultiplication( T( M(x64:[1, 2, 3, 4] as X)), T(M(x64:[2, 0, 0, 0] as X)), T(M(x64:[ 2, 4, 6, 8, 0, 0, 0, 0] as X))) + NBKAssertMultiplication( T( M(x64:[1, 2, 3, 4] as X)), -T(M(x64:[0, 2, 0, 0] as X)), -T(M(x64:[ 0, 2, 4, 6, 8, 0, 0, 0] as X))) + NBKAssertMultiplication(-T( M(x64:[1, 2, 3, 4] as X)), T(M(x64:[0, 0, 2, 0] as X)), -T(M(x64:[ 0, 0, 2, 4, 6, 8, 0, 0] as X))) + NBKAssertMultiplication(-T( M(x64:[1, 2, 3, 4] as X)), -T(M(x64:[0, 0, 0, 2] as X)), T(M(x64:[ 0, 0, 0, 2, 4, 6, 8, 0] as X))) + + NBKAssertMultiplication( T(~M(x64:[1, 2, 3, 4] as X)), T(M(x64:[2, 0, 0, 0] as X)), T(M(x64:[~3, ~4, ~6, ~8, 1, 0, 0, 0] as X))) + NBKAssertMultiplication( T(~M(x64:[1, 2, 3, 4] as X)), -T(M(x64:[0, 2, 0, 0] as X)), -T(M(x64:[ 0, ~3, ~4, ~6, ~8, 1, 0, 0] as X))) + NBKAssertMultiplication(-T(~M(x64:[1, 2, 3, 4] as X)), T(M(x64:[0, 0, 2, 0] as X)), -T(M(x64:[ 0, 0, ~3, ~4, ~6, ~8, 1, 0] as X))) + NBKAssertMultiplication(-T(~M(x64:[1, 2, 3, 4] as X)), -T(M(x64:[0, 0, 0, 2] as X)), T(M(x64:[ 0, 0, 0, ~3, ~4, ~6, ~8, 1] as X))) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Digit (and Self) + //=------------------------------------------------------------------------= + + func testMultiplyingLargeBySmall() { + NBKAssertMultiplicationByDigit( T( M(words:[1, 2, 3, 4] as W)), D(0), T( M(words:[ 0, 0, 0, 0, 0] as W))) + NBKAssertMultiplicationByDigit( T( M(words:[1, 2, 3, 4] as W)), -D(1), -T( M(words:[ 1, 2, 3, 4, 0] as W))) + NBKAssertMultiplicationByDigit(-T( M(words:[1, 2, 3, 4] as W)), D(2), -T( M(words:[ 2, 4, 6, 8, 0] as W))) + NBKAssertMultiplicationByDigit(-T( M(words:[1, 2, 3, 4] as W)), -D(3), T( M(words:[ 3, 6, 9, 12, 0] as W))) + + NBKAssertMultiplicationByDigit( T(~M(words:[1, 2, 3, 4] as W)), D(0), T(~M(words:[~0, ~0, ~0, ~0, ~0] as W))) + NBKAssertMultiplicationByDigit( T(~M(words:[1, 2, 3, 4] as W)), -D(1), -T(~M(words:[ 1, 2, 3, 4, ~0] as W))) + NBKAssertMultiplicationByDigit(-T(~M(words:[1, 2, 3, 4] as W)), D(2), -T(~M(words:[ 3, 4, 6, 8, ~1] as W))) + NBKAssertMultiplicationByDigit(-T(~M(words:[1, 2, 3, 4] as W)), -D(3), T(~M(words:[ 5, 6, 9, 12, ~2] as W))) + } + + //=------------------------------------------------------------------------= + // MARK: Tests x Miscellaneous + //=------------------------------------------------------------------------= + + func testOverloadsAreUnambiguousWhenUsingIntegerLiterals() { + func becauseThisCompilesSuccessfully(_ x: inout T) { + XCTAssertNotNil(x *= 0) + XCTAssertNotNil(x * 0) + } + } +} + +//*============================================================================* +// MARK: * NBK x Signed x Addition x Assertions +//*============================================================================* + +private func NBKAssertMultiplication( +_ lhs: NBKSigned, _ rhs: NBKSigned, _ result: NBKSigned, +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) +} + +private func NBKAssertMultiplicationByDigit( +_ lhs: NBKSigned, _ rhs: NBKSigned.Digit, _ result: NBKSigned, +file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + NBKAssertMultiplication(lhs, NBKSigned(digit: rhs), result) + //=------------------------------------------= + XCTAssertEqual( lhs * rhs, result, file: file, line: line) + XCTAssertEqual({ var lhs = lhs; lhs *= rhs; return lhs }(), result, file: file, line: line) +} + +#endif diff --git a/Tests/NBKSignedKitTests/NBKSigned+Subtract.swift b/Tests/NBKSignedKitTests/NBKSigned+Subtract.swift index ad24326d..38117a4d 100644 --- a/Tests/NBKSignedKitTests/NBKSigned+Subtract.swift +++ b/Tests/NBKSignedKitTests/NBKSigned+Subtract.swift @@ -33,7 +33,7 @@ final class NBKSignedTestsOnSubtractionAsSIntXL: XCTestCase { // MARK: Tests //=------------------------------------------------------------------------= - func testSubtracting() { + func testSubtractingLargeFromLarge() { NBKAssertSubtraction( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[3, 0, 0, 0] as X)), T(M(x64:[~3, ~0, ~0, 0] as X))) NBKAssertSubtraction( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[0, 3, 0, 0] as X)), T(M(x64:[~0, ~3, ~0, 0] as X))) NBKAssertSubtraction( T(M(x64:[~0, ~0, ~0, 0] as X)), T(M(x64:[0, 0, 3, 0] as X)), T(M(x64:[~0, ~0, ~3, 0] as X))) @@ -56,10 +56,10 @@ final class NBKSignedTestsOnSubtractionAsSIntXL: XCTestCase { } //=------------------------------------------------------------------------= - // MARK: Tests x Digit + // MARK: Tests x Digit (and Self) //=------------------------------------------------------------------------= - func testSubtractingDigit() { + func testSubtractingSmallFromSmall() { NBKAssertSubtractionByDigit( T(M(1)), D(U(2)), -T(M(1))) NBKAssertSubtractionByDigit( T(M(1)), D(U(1)), T(M(0))) NBKAssertSubtractionByDigit( T(M(1)), D(U(0)), T(M(1))) @@ -116,11 +116,11 @@ file: StaticString = #file, line: UInt = #line) { private func NBKAssertSubtractionByDigit( _ lhs: NBKSigned, _ rhs: NBKSigned.Digit, _ partialValue: NBKSigned, file: StaticString = #file, line: UInt = #line) { + //=------------------------------------------= + NBKAssertSubtraction(lhs, NBKSigned(digit: rhs), partialValue) //=------------------------------------------= NBKAssertIdentical( lhs - rhs, partialValue, file: file, line: line) NBKAssertIdentical({ var lhs = lhs; lhs -= rhs; return lhs }(), partialValue, file: file, line: line) - //=------------------------------------------= - NBKAssertSubtraction(lhs, NBKSigned(digit: rhs), partialValue) } #endif