From dd3eec425be129408122aa536767c605fe27916b Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Thu, 20 Feb 2020 09:56:32 -0500 Subject: [PATCH 01/13] Reduced generic constraint on Complex scalar type from BinaryFloatingPoint to Numeric --- .swiftlint.yml | 1 + Complex.xcodeproj/project.pbxproj | 57 + Sources/Complex/Complex.swift | 338 +++--- Sources/Complex/ComplexArithmetic.swift | 191 +++ Sources/Complex/Functions.swift | 26 +- .../ComplexTests/ComplexArithmeticTests.swift | 365 ++++++ Tests/ComplexTests/ComplexTests.swift | 1045 ++++++----------- Tests/ComplexTests/FunctionsTests.swift | 12 - 8 files changed, 1135 insertions(+), 900 deletions(-) create mode 100644 Sources/Complex/ComplexArithmetic.swift create mode 100644 Tests/ComplexTests/ComplexArithmeticTests.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index 6295eef..fb627d6 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -59,5 +59,6 @@ reporter: "xcode" identifier_name: excluded: + - i - pi - _value diff --git a/Complex.xcodeproj/project.pbxproj b/Complex.xcodeproj/project.pbxproj index ff42a42..dd8fccd 100644 --- a/Complex.xcodeproj/project.pbxproj +++ b/Complex.xcodeproj/project.pbxproj @@ -38,12 +38,40 @@ DDB8122123F656AC0079FEB5 /* FunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */; }; DDB8122223F656AC0079FEB5 /* FunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */; }; DDB8122323F656AC0079FEB5 /* FunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */; }; + DDB8126223F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; + DDB8126323F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; + DDB8126423F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; + DDB8126523F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; + DDB8126723F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */; }; + DDB8126823F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */; }; + DDB8126923F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */; }; DDFEEC3D23EF13910096015C /* Complex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDFEEC3323EF13900096015C /* Complex.framework */; }; DDFEECC723F2001A0096015C /* Complex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDFEECBE23F2001A0096015C /* Complex.framework */; }; DDFEECE323F2003E0096015C /* Complex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DDFEECDA23F2003E0096015C /* Complex.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + DDB8127B23FA5C3E0079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDFEECA423F1BA0B0096015C; + remoteInfo = "Run SwiftLint"; + }; + DDB8127F23FA5C430079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDFEECA423F1BA0B0096015C; + remoteInfo = "Run SwiftLint"; + }; + DDB8128323FA5C480079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDFEECA423F1BA0B0096015C; + remoteInfo = "Run SwiftLint"; + }; DDFEEC3E23EF13910096015C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DDFEEC2A23EF13900096015C /* Project object */; @@ -83,6 +111,8 @@ DDB8121B23F63B890079FEB5 /* Half.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Half.framework; path = Carthage/Build/Mac/Half.framework; sourceTree = ""; }; DDB8121C23F63B900079FEB5 /* Half.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Half.framework; path = Carthage/Build/iOS/Half.framework; sourceTree = ""; }; DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionsTests.swift; sourceTree = ""; }; + DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexArithmetic.swift; sourceTree = ""; }; + DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexArithmeticTests.swift; sourceTree = ""; }; DDFEEC3323EF13900096015C /* Complex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Complex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DDFEEC3723EF13900096015C /* Complex-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Complex-Info.plist"; path = "Info/Complex-Info.plist"; sourceTree = ""; }; DDFEEC3C23EF13910096015C /* ComplexTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ComplexTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -214,6 +244,7 @@ isa = PBXGroup; children = ( DDB8121023F5AEB10079FEB5 /* ComplexTests.swift */, + DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */, DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */, DDFEEC4323EF13910096015C /* ComplexTests-Info.plist */, ); @@ -247,6 +278,7 @@ isa = PBXGroup; children = ( DDB8120623F59B760079FEB5 /* Complex.swift */, + DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */, DDB8120B23F5A8E80079FEB5 /* Functions.swift */, ); path = Complex; @@ -335,6 +367,7 @@ buildRules = ( ); dependencies = ( + DDB8127C23FA5C3E0079FEB5 /* PBXTargetDependency */, ); name = "Complex macOS"; productName = "Complex macOS"; @@ -371,6 +404,7 @@ buildRules = ( ); dependencies = ( + DDB8128023FA5C430079FEB5 /* PBXTargetDependency */, ); name = "Complex tvOS"; productName = "Complex tvOS"; @@ -407,6 +441,7 @@ buildRules = ( ); dependencies = ( + DDB8128423FA5C480079FEB5 /* PBXTargetDependency */, ); name = "Complex watchOS"; productName = "Complex watchOS"; @@ -559,6 +594,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126223F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, DDB8120723F59B760079FEB5 /* Complex.swift in Sources */, DDB8120C23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -568,6 +604,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126723F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, DDB8121123F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122123F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -577,6 +614,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126323F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, DDB8120823F59B760079FEB5 /* Complex.swift in Sources */, DDB8120D23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -586,6 +624,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126823F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, DDB8121223F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122223F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -595,6 +634,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126423F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, DDB8120923F59B760079FEB5 /* Complex.swift in Sources */, DDB8120E23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -604,6 +644,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126923F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, DDB8121323F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122323F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -613,6 +654,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + DDB8126523F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, DDB8120A23F59B760079FEB5 /* Complex.swift in Sources */, DDB8120F23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -621,6 +663,21 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + DDB8127C23FA5C3E0079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDFEECA423F1BA0B0096015C /* Run SwiftLint */; + targetProxy = DDB8127B23FA5C3E0079FEB5 /* PBXContainerItemProxy */; + }; + DDB8128023FA5C430079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDFEECA423F1BA0B0096015C /* Run SwiftLint */; + targetProxy = DDB8127F23FA5C430079FEB5 /* PBXContainerItemProxy */; + }; + DDB8128423FA5C480079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDFEECA423F1BA0B0096015C /* Run SwiftLint */; + targetProxy = DDB8128323FA5C480079FEB5 /* PBXContainerItemProxy */; + }; DDFEEC3F23EF13910096015C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DDFEEC3223EF13900096015C /* Complex */; diff --git a/Sources/Complex/Complex.swift b/Sources/Complex/Complex.swift index fc4b913..1c35f8b 100644 --- a/Sources/Complex/Complex.swift +++ b/Sources/Complex/Complex.swift @@ -7,91 +7,149 @@ import Foundation -//swiftlint:disable shorthand_operator - // MARK: - Complex Definition -@frozen public struct Complex { +@frozen public struct Complex { // MARK: Public Properties - public var real: FloatingPoint - public var imaginary: FloatingPoint + public var real: Scalar + public var imaginary: Scalar // MARK: Initialization @_transparent - public init(real: FloatingPoint = 0.0, imaginary: FloatingPoint = 0.0) { + public init(real: Scalar = .zero, imaginary: Scalar = .zero) { self.real = real self.imaginary = imaginary } @_transparent - public init(real: Source, imaginary: Source) where Source: BinaryFloatingPoint { - self.init(real: FloatingPoint(real), imaginary: FloatingPoint(imaginary)) + public init(_ other: Complex) { + self.real = other.real + self.imaginary = other.imaginary } @_transparent - public init(real: Source, imaginary: Source) where Source: BinaryInteger { - self.init(real: FloatingPoint(real), imaginary: FloatingPoint(imaginary)) + public init() { + self.init(real: .zero, imaginary: .zero) } +} + +// MARK: - Complex Initialization Extensions + +extension Complex where Scalar: BinaryFloatingPoint { @_transparent - public init(_ complex: Complex) where Source: BinaryFloatingPoint { - self.init(real: FloatingPoint(complex.real), imaginary: FloatingPoint(complex.imaginary)) + public init(real: Source, imaginary: Source) where Source: BinaryFloatingPoint { + self.init(real: Scalar(real), imaginary: Scalar(imaginary)) } @_transparent - public init() { - self.init(real: 0.0, imaginary: 0.0) + public init(_ other: Complex) where Source: BinaryFloatingPoint { + self.init(real: Scalar(other.real), imaginary: Scalar(other.imaginary)) } } -// MARK: - ExpressibleByArrayLiteral Protocol Conformance - -extension Complex: ExpressibleByArrayLiteral { +extension Complex where Scalar: FloatingPoint { @_transparent - public init(arrayLiteral elements: FloatingPoint...) { - precondition(elements.count <= 2, "Expected at most two elements") + public init(real: Source, imaginary: Source) where Source: BinaryInteger { + self.init(real: Scalar(real), imaginary: Scalar(imaginary)) + } - if elements.isEmpty { - self.init() - } else if elements.count == 1 { - self.init(real: elements[0]) - } else { - self.init(real: elements[0], imaginary: elements[1]) - } + @_transparent + public init(_ other: Complex) where Source: BinaryInteger { + self.init(real: Scalar(other.real), imaginary: Scalar(other.imaginary)) } } -// MARK: - AdditiveArithmetic Protocol Conformance +extension Complex where Scalar: BinaryFloatingPoint, Scalar.RawSignificand: FixedWidthInteger { + + @inlinable + public static func random(in range: Range, using generator: inout T) -> Complex where T: RandomNumberGenerator { + return Complex(real: Scalar.random(in: range, using: &generator), imaginary: Scalar.random(in: range, using: &generator)) + } + + @inlinable + public static func random(in range: Range) -> Complex { + return Complex(real: Scalar.random(in: range), imaginary: Scalar.random(in: range)) + } + + @inlinable + public static func random(in range: ClosedRange, using generator: inout T) -> Complex where T: RandomNumberGenerator { + return Complex(real: Scalar.random(in: range, using: &generator), imaginary: Scalar.random(in: range, using: &generator)) + } + + @inlinable + public static func random(in range: ClosedRange) -> Complex { + return Complex(real: Scalar.random(in: range), imaginary: Scalar.random(in: range)) + } +} -extension Complex: AdditiveArithmetic { +extension Complex where Scalar: BinaryInteger { @_transparent - public static var zero: Complex { - return Complex(real: .zero, imaginary: .zero) + public init(real: Source, imaginary: Source) where Source: BinaryFloatingPoint { + self.init(real: Scalar(real), imaginary: Scalar(imaginary)) } @_transparent - public static func + (lhs: Complex, rhs: Complex) -> Complex { - return Complex(real: lhs.real + rhs.real, imaginary: lhs.imaginary + rhs.imaginary) + public init(real: Source, imaginary: Source) where Source: BinaryInteger { + self.init(real: Scalar(real), imaginary: Scalar(imaginary)) } + // + @_transparent - public static func += (lhs: inout Complex, rhs: Complex) { - lhs = lhs + rhs + public init(_ other: Complex) where Source: BinaryFloatingPoint { + self.init(real: Scalar(other.real), imaginary: Scalar(other.imaginary)) } @_transparent - public static func - (lhs: Complex, rhs: Complex) -> Complex { - return Complex(real: lhs.real - rhs.real, imaginary: lhs.imaginary - rhs.imaginary) + public init(_ other: Complex) where Source: BinaryInteger { + self.init(real: Scalar(other.real), imaginary: Scalar(other.imaginary)) + } +} + +extension Complex where Scalar: FixedWidthInteger { + + @inlinable + public static func random(in range: Range, using generator: inout T) -> Complex where T: RandomNumberGenerator { + return Complex(real: Scalar.random(in: range, using: &generator), imaginary: Scalar.random(in: range, using: &generator)) + } + + @inlinable + public static func random(in range: Range) -> Complex { + return Complex(real: Scalar.random(in: range), imaginary: Scalar.random(in: range)) } + @inlinable + public static func random(in range: ClosedRange, using generator: inout T) -> Complex where T: RandomNumberGenerator { + return Complex(real: Scalar.random(in: range, using: &generator), imaginary: Scalar.random(in: range, using: &generator)) + } + + @inlinable + public static func random(in range: ClosedRange) -> Complex { + return Complex(real: Scalar.random(in: range), imaginary: Scalar.random(in: range)) + } +} + +// MARK: - ExpressibleByArrayLiteral Protocol Conformance + +extension Complex: ExpressibleByArrayLiteral where Scalar: AdditiveArithmetic { + @_transparent - public static func -= (lhs: inout Complex, rhs: Complex) { - lhs = lhs - rhs + public init(arrayLiteral elements: Scalar...) { + precondition(elements.count <= 2, "Expected at most two elements") + + if elements.isEmpty { + self.init() + } else if elements.count == 1 { + self.init(real: elements[0], imaginary: .zero) + } else { + self.init(real: elements[0], imaginary: elements[1]) + } } } @@ -99,6 +157,7 @@ extension Complex: AdditiveArithmetic { extension Complex: CustomStringConvertible { + @_transparent public var description: String { return "{ real: \(real), imaginary: \(imaginary) }" } @@ -108,6 +167,7 @@ extension Complex: CustomStringConvertible { extension Complex: CustomDebugStringConvertible { + @_transparent public var debugDescription: String { return "{ real: \(real), imaginary: \(imaginary) }" } @@ -115,7 +175,7 @@ extension Complex: CustomDebugStringConvertible { // MARK: - Hashable Protocol Conformance -extension Complex: Hashable { +extension Complex: Hashable where Scalar: Hashable { @inlinable public func hash(into hasher: inout Hasher) { @@ -126,7 +186,7 @@ extension Complex: Hashable { // MARK: - Equatable Protocol Conformance -extension Complex: Equatable { +extension Complex: Equatable where Scalar: Equatable { @_transparent public static func == (lhs: Complex, rhs: Complex) -> Bool { @@ -134,134 +194,114 @@ extension Complex: Equatable { } } -// MARK: - Codable Protocol Conformance +// MARK: - Encodable Protocol Conformance -extension Complex: Codable where FloatingPoint: Codable { +extension Complex: Encodable where Scalar: Encodable { } -// MARK: - Complex Extension +// MARK: - Decodable Protocol Conformance -extension Complex { +extension Complex: Decodable where Scalar: Decodable { - @_transparent - public static func * (lhs: Complex, rhs: Complex) -> Complex { - let real = (lhs.real * rhs.real) - (lhs.imaginary * rhs.imaginary) - let imaginary = (lhs.real * rhs.imaginary) + (lhs.imaginary * rhs.real) +} - return Complex(real: real, imaginary: imaginary) - } +// MARK: - Complex BinaryInteger Extensions - @_transparent - public static func *= (lhs: inout Complex, rhs: Complex) { - lhs = lhs * rhs - } +extension Complex where Scalar: BinaryInteger { @_transparent - public static func / (lhs: Complex, rhs: Complex) -> Complex { - let numerator = lhs * rhs.conjugate() - let denominator = rhs * rhs.conjugate() // Multiplying the denominator by its conjugate cancels out its imaginary component - - return Complex(real: numerator.real / denominator.real, imaginary: numerator.imaginary / denominator.real) + public var modulus: Scalar { + return Scalar(sqrt(Float80(real * real + imaginary * imaginary))) } @_transparent - public static func /= (lhs: inout Complex, rhs: Complex) { - lhs = lhs / rhs + public var angle: Scalar { + return Scalar(atan2(Float80(imaginary), Float80(real))) } -} - -// MARK: - Complex Extension -extension Complex { + // @_transparent - public static func + (lhs: Complex, rhs: FloatingPoint) -> Complex { - return Complex(real: lhs.real + rhs, imaginary: lhs.imaginary) - } + public func string(withNotation notation: Notation) -> String { + let string: String - @_transparent - public static func + (lhs: FloatingPoint, rhs: Complex) -> Complex { - return Complex(real: lhs + rhs.real, imaginary: rhs.imaginary) - } + switch notation { + case .square: string = "\(real) + \(imaginary)i" + case .trigonometric: string = "\(modulus) (cos(\(angle)) + i sin(\(angle)))" + case .euler: string = "\(modulus) e ^ (i \(angle))" + case .angle: string = "\(modulus) ⦣ \(angle)" + } - @_transparent - public static func += (lhs: inout Complex, rhs: FloatingPoint) { - lhs = lhs + rhs + return string } +} - @_transparent - public static func - (lhs: Complex, rhs: FloatingPoint) -> Complex { - return Complex(real: lhs.real - rhs, imaginary: lhs.imaginary) - } +// MARK: - Complex FloatingPoint Extensions - @_transparent - public static func - (lhs: FloatingPoint, rhs: Complex) -> Complex { - return Complex(real: lhs - rhs.real, imaginary: -rhs.imaginary) - } +extension Complex where Scalar: FloatingPoint { @_transparent - public static func -= (lhs: inout Complex, rhs: FloatingPoint) { - lhs = lhs - rhs + public func rounded(_ rule: FloatingPointRoundingRule) -> Complex { + var complex = self + complex.round(rule) + return complex } @_transparent - public static func * (lhs: Complex, rhs: FloatingPoint) -> Complex { - return Complex(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs) + public func rounded() -> Complex { + rounded(.toNearestOrAwayFromZero) } - @_transparent - public static func * (lhs: FloatingPoint, rhs: Complex) -> Complex { - return Complex(real: lhs * rhs.real, imaginary: lhs * rhs.imaginary) - } + // @_transparent - public static func *= (lhs: inout Complex, rhs: FloatingPoint) { - lhs = lhs * rhs + public mutating func round(_ rule: FloatingPointRoundingRule) { + real.round(rule) + imaginary.round(rule) } @_transparent - public static func / (lhs: Complex, rhs: FloatingPoint) -> Complex { - return Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs) + public mutating func round() { + self.round(.toNearestOrAwayFromZero) } +} - @_transparent - public static func / (lhs: FloatingPoint, rhs: Complex) -> Complex { - return Complex(real: lhs, imaginary: 0.0) / rhs - } +extension Complex where Scalar: FloatingPoint { @_transparent - public static func /= (lhs: inout Complex, rhs: FloatingPoint) { - lhs = lhs / rhs + public var modulus: Scalar { + return sqrt(real * real + imaginary * imaginary) } } -// MARK: - Complex Extension +// MARK: - Complex BinaryFloatingPoint Extensions -extension Complex { +extension Complex where Scalar: BinaryFloatingPoint { @_transparent - public mutating func negate() { - real.negate() - imaginary.negate() + public var angle: Scalar { + return Scalar(atan2(Float80(imaginary), Float80(real))) } @_transparent - public static prefix func - (complex: Complex) -> Complex { - var value = complex - value.negate() - return value - } + public func string(withNotation notation: Notation) -> String { + let string: String - @_transparent - public static prefix func + (complex: Complex) -> Complex { - return complex + switch notation { + case .square: string = "\(real) + \(imaginary)i" + case .trigonometric: string = "\(modulus) (cos(\(angle)) + i sin(\(angle)))" + case .euler: string = "\(modulus) e ^ (i \(angle))" + case .angle: string = "\(modulus) ⦣ \(angle)" + } + + return string } } -// MARK: - Complex Extension +// MARK: - Complex SignedNumeric Extensions -extension Complex { +extension Complex where Scalar: SignedNumeric { @_transparent public static prefix func ~ (complex: Complex) -> Complex { @@ -275,62 +315,55 @@ extension Complex { return complex } + @_transparent public mutating func formConjugate() { imaginary.negate() } } -// MARK: - Complex Extension - -extension Complex { +extension Complex where Scalar: SignedNumeric { @_transparent - public func rounded(_ rule: FloatingPointRoundingRule) -> Complex { - var complex = self - complex.round(rule) - return complex + public mutating func negate() { + real.negate() + imaginary.negate() } @_transparent - public func rounded() -> Complex { - var complex = self - complex.round() - return complex + public static prefix func - (complex: Complex) -> Complex { + var value = complex + value.negate() + return value } +} - // +// MARK: - Complex Extensions - @_transparent - public mutating func round(_ rule: FloatingPointRoundingRule) { - real.round(rule) - imaginary.round(rule) - } +extension Complex { @_transparent - public mutating func round() { - self.round(.toNearestOrAwayFromZero) + public static var i: Complex { + return Complex(real: .zero, imaginary: 1) } } -// MARK: - Complex Extension - extension Complex { @_transparent - public var modulus: FloatingPoint { - return sqrt(real * real + imaginary * imaginary) + public static var one: Complex { + return Complex(real: 1, imaginary: .zero) } +} - public var angle: FloatingPoint { -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - return FloatingPoint(atan2(Float80(imaginary), Float80(real))) -#else - return FloatingPoint(atan2(Double(imaginary), Double(real))) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) +extension Complex { + + @inlinable @inline(__always) + public static prefix func + (complex: Complex) -> Complex { + return complex } } -// MARK: - Complex Extension +// MARK: - Complex.Notation Definition extension Complex { @@ -341,17 +374,4 @@ extension Complex { case euler case angle } - - public func string(withNotation notation: Notation) -> String { - let string: String - - switch notation { - case .square: string = "\(real) + \(imaginary)i" - case .trigonometric: string = "\(modulus) (cos(\(angle)) + i sin(\(angle)))" - case .euler: string = "\(modulus) e ^ (i \(angle))" - case .angle: string = "\(modulus) ⦣ \(angle)" - } - - return string - } } diff --git a/Sources/Complex/ComplexArithmetic.swift b/Sources/Complex/ComplexArithmetic.swift new file mode 100644 index 0000000..b71399e --- /dev/null +++ b/Sources/Complex/ComplexArithmetic.swift @@ -0,0 +1,191 @@ +// +// ComplexArithmetic.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +import Foundation + +//swiftlint:disable shorthand_operator + +// MARK: - AdditiveArithmetic Protocol Conformance + +extension Complex: AdditiveArithmetic { + + @_transparent + public static var zero: Complex { + return Complex(real: .zero, imaginary: .zero) + } + + @_transparent + public static func + (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real + rhs.real, imaginary: lhs.imaginary + rhs.imaginary) + } + + @_transparent + public static func += (lhs: inout Complex, rhs: Complex) { + lhs = lhs + rhs + } + + @_transparent + public static func - (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real - rhs.real, imaginary: lhs.imaginary - rhs.imaginary) + } + + @_transparent + public static func -= (lhs: inout Complex, rhs: Complex) { + lhs = lhs - rhs + } +} + +// MARK: - Addition/Subtraction + +extension Complex { + + @_transparent + public static func + (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real + rhs, imaginary: lhs.imaginary) + } + + @_transparent + public static func + (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs + rhs.real, imaginary: rhs.imaginary) + } + + @_transparent + public static func += (lhs: inout Complex, rhs: Scalar) { + lhs = lhs + rhs + } + + // + + @_transparent + public static func - (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real - rhs, imaginary: lhs.imaginary) + } + + @_transparent + public static func -= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs - rhs + } +} + +extension Complex where Scalar: SignedNumeric { + + @_transparent + public static func - (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs - rhs.real, imaginary: -rhs.imaginary) + } +} + +// MARK: - Multiplication + +extension Complex { + + @_transparent + public static func * (lhs: Complex, rhs: Complex) -> Complex { + let real = (lhs.real * rhs.real) - (lhs.imaginary * rhs.imaginary) + let imaginary = (lhs.real * rhs.imaginary) + (lhs.imaginary * rhs.real) + + return Complex(real: real, imaginary: imaginary) + } + + @_transparent + public static func *= (lhs: inout Complex, rhs: Complex) { + lhs = lhs * rhs + } + + // + + @_transparent + public static func * (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs) + } + + @_transparent + public static func * (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs * rhs.real, imaginary: lhs * rhs.imaginary) + } + + @_transparent + public static func *= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs * rhs + } +} + +// MARK: - Division (BinaryInteger) + +extension Complex where Scalar: BinaryInteger { + + @_transparent + public static func / (lhs: Complex, rhs: Complex) -> Complex { + let real = (lhs.real * rhs.real + lhs.imaginary * rhs.imaginary) + let imaginary = (lhs.imaginary * rhs.real - lhs.real * rhs.imaginary) + let denominator = (rhs.real * rhs.real) + (rhs.imaginary * rhs.imaginary) + + return Complex(real: real / denominator, imaginary: imaginary / denominator) + } + + @_transparent + public static func /= (lhs: inout Complex, rhs: Complex) { + lhs = lhs / rhs + } + + // + + @_transparent + public static func / (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs) + } + + @_transparent + public static func /= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs / rhs + } +} + +// MARK: - Division (SignedInteger) + +extension Complex where Scalar: SignedInteger { + + @_transparent + public static func / (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs, imaginary: .zero) / rhs + } +} + +// MARK: - Division (FloatingPoint) + +extension Complex where Scalar: FloatingPoint { + + @_transparent + public static func / (lhs: Complex, rhs: Complex) -> Complex { + let numerator = lhs * rhs.conjugate() + let denominator = rhs * rhs.conjugate() // Multiplying the denominator by its conjugate cancels out its imaginary component + + return Complex(real: numerator.real / denominator.real, imaginary: numerator.imaginary / denominator.real) + } + + @_transparent + public static func /= (lhs: inout Complex, rhs: Complex) { + lhs = lhs / rhs + } + + // + + @_transparent + public static func / (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs) + } + + @_transparent + public static func / (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs, imaginary: .zero) / rhs + } + + @_transparent + public static func /= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs / rhs + } +} diff --git a/Sources/Complex/Functions.swift b/Sources/Complex/Functions.swift index 2f9d083..6aada0d 100644 --- a/Sources/Complex/Functions.swift +++ b/Sources/Complex/Functions.swift @@ -8,56 +8,56 @@ import Foundation @_transparent -public func csqrt(_ value: F) -> Complex where F: BinaryFloatingPoint { +public func csqrt(_ value: F) -> Complex where F: FloatingPoint { let complex: Complex if value < 0 { - complex = Complex(real: 0.0, imaginary: sqrt(-value)) + complex = Complex(real: .zero, imaginary: sqrt(-value)) } else { - complex = Complex(real: sqrt(value), imaginary: 0.0) + complex = Complex(real: sqrt(value), imaginary: .zero) } return complex } @_transparent -public func sqrt(_ value: Complex) -> Complex where F: BinaryFloatingPoint { +public func sqrt(_ value: Complex) -> Complex where F: FloatingPoint { //swiftlint:disable opening_brace statement_position let sign = { (value: F) -> F in let sign: F - if value < 0.0 { sign = -1.0 } - else { sign = 1.0 } + if value < .zero { sign = -1 } + else { sign = 1 } return sign } //swiftlint:enable opening_brace statement_position let modulus = value.modulus - let real = sqrt((value.real + modulus) * 0.5) - let imaginary = sign(value.imaginary) * sqrt((modulus - value.real) * 0.5) + let real = sqrt((value.real + modulus) / F(2)) + let imaginary = sign(value.imaginary) * sqrt((modulus - value.real) / F(2)) return Complex(real: real, imaginary: imaginary) } @_transparent -public func abs(_ value: Complex) -> Complex where F: BinaryFloatingPoint { +public func abs(_ value: Complex) -> Complex where F: Comparable, F: SignedNumeric { return Complex(real: abs(value.real), imaginary: abs(value.imaginary)) } @_transparent -public func min(_ lhs: Complex, _ rhs: Complex) -> Complex where F: BinaryFloatingPoint { +public func min(_ lhs: Complex, _ rhs: Complex) -> Complex where F: Comparable { return Complex(real: min(lhs.real, rhs.real), imaginary: min(lhs.imaginary, rhs.imaginary)) } @_transparent -public func max(_ lhs: Complex, _ rhs: Complex) -> Complex where F: BinaryFloatingPoint { +public func max(_ lhs: Complex, _ rhs: Complex) -> Complex where F: Comparable { return Complex(real: max(lhs.real, rhs.real), imaginary: max(lhs.imaginary, rhs.imaginary)) } @_transparent -public func clamp(_ value: Complex, _ minimum: F, _ maximum: F) -> Complex where F: BinaryFloatingPoint { +public func clamp(_ value: Complex, _ minimum: F, _ maximum: F) -> Complex where F: Comparable { return Complex(real: max(minimum, min(value.real, maximum)), imaginary: max(minimum, min(value.imaginary, maximum))) } @_transparent -public func clamp(_ value: Complex, _ minimum: Complex, _ maximum: Complex) -> Complex where F: BinaryFloatingPoint { +public func clamp(_ value: Complex, _ minimum: Complex, _ maximum: Complex) -> Complex where F: Comparable { return Complex(real: max(minimum.real, min(value.real, maximum.real)), imaginary: max(minimum.imaginary, min(value.imaginary, maximum.imaginary))) } diff --git a/Tests/ComplexTests/ComplexArithmeticTests.swift b/Tests/ComplexTests/ComplexArithmeticTests.swift new file mode 100644 index 0000000..4a3f25d --- /dev/null +++ b/Tests/ComplexTests/ComplexArithmeticTests.swift @@ -0,0 +1,365 @@ +// +// ComplexArithmeticTests.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +@testable import Complex +import Half +import XCTest + +class ComplexArithmeticTests: XCTestCase { + + // MARK: Test Methods + + func testAdditionWithZero() { + testAdditionWithZero(Complex(real: Int8(1), imaginary: Int8(-4))) + testAdditionWithZero(Complex(real: Int16(1), imaginary: Int16(-4))) + testAdditionWithZero(Complex(real: Int32(1), imaginary: Int32(-4))) + testAdditionWithZero(Complex(real: Int64(1), imaginary: Int64(-4))) + testAdditionWithZero(Complex(real: Int(1), imaginary: Int(-4))) + testAdditionWithZero(Complex(real: UInt8(7), imaginary: UInt8(13))) + testAdditionWithZero(Complex(real: UInt16(7), imaginary: UInt16(13))) + testAdditionWithZero(Complex(real: UInt32(7), imaginary: UInt32(13))) + testAdditionWithZero(Complex(real: UInt64(7), imaginary: UInt64(13))) + testAdditionWithZero(Complex(real: UInt(7), imaginary: UInt(13))) + testAdditionWithZero(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testAdditionWithZero(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testAdditionWithZero(Complex(real: Double(8.9), imaginary: Double(10.8))) + testAdditionWithZero(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } + + func testSubtractionWithZero() { + testSubtractionWithZero(Complex(real: Int8(1), imaginary: Int8(-4))) + testSubtractionWithZero(Complex(real: Int16(1), imaginary: Int16(-4))) + testSubtractionWithZero(Complex(real: Int32(1), imaginary: Int32(-4))) + testSubtractionWithZero(Complex(real: Int64(1), imaginary: Int64(-4))) + testSubtractionWithZero(Complex(real: Int(1), imaginary: Int(-4))) + testSubtractionWithZero(Complex(real: UInt8(7), imaginary: UInt8(13))) + testSubtractionWithZero(Complex(real: UInt16(7), imaginary: UInt16(13))) + testSubtractionWithZero(Complex(real: UInt32(7), imaginary: UInt32(13))) + testSubtractionWithZero(Complex(real: UInt64(7), imaginary: UInt64(13))) + testSubtractionWithZero(Complex(real: UInt(7), imaginary: UInt(13))) + testSubtractionWithZero(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testSubtractionWithZero(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testSubtractionWithZero(Complex(real: Double(8.9), imaginary: Double(10.8))) + testSubtractionWithZero(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } + + func testMultiplicationWithZero() { + testMultiplicationWithZero(Complex(real: Int8(1), imaginary: Int8(-4))) + testMultiplicationWithZero(Complex(real: Int16(1), imaginary: Int16(-4))) + testMultiplicationWithZero(Complex(real: Int32(1), imaginary: Int32(-4))) + testMultiplicationWithZero(Complex(real: Int64(1), imaginary: Int64(-4))) + testMultiplicationWithZero(Complex(real: Int(1), imaginary: Int(-4))) + testMultiplicationWithZero(Complex(real: UInt8(7), imaginary: UInt8(13))) + testMultiplicationWithZero(Complex(real: UInt16(7), imaginary: UInt16(13))) + testMultiplicationWithZero(Complex(real: UInt32(7), imaginary: UInt32(13))) + testMultiplicationWithZero(Complex(real: UInt64(7), imaginary: UInt64(13))) + testMultiplicationWithZero(Complex(real: UInt(7), imaginary: UInt(13))) + testMultiplicationWithZero(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testMultiplicationWithZero(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testMultiplicationWithZero(Complex(real: Double(8.9), imaginary: Double(10.8))) + testMultiplicationWithZero(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } + + func testAddition() { + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1, imaginary: 2), Complex(real: 3, imaginary: 4), Complex(real: 4, imaginary: 6)) + testAddition(Complex(real: 1.0, imaginary: 2.0), Complex(real: 3.0, imaginary: 4.0), Complex(real: 4.0, imaginary: 6.0)) + testAddition(Complex(real: 1.0, imaginary: 2.0), Complex(real: 3.0, imaginary: 4.0), Complex(real: 4.0, imaginary: 6.0)) + testAddition(Complex(real: 1.0, imaginary: 2.0), Complex(real: 3.0, imaginary: 4.0), Complex(real: 4.0, imaginary: 6.0)) + testAddition(Complex(real: 1.0, imaginary: 2.0), Complex(real: 3.0, imaginary: 4.0), Complex(real: 4.0, imaginary: 6.0)) + + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1, imaginary: 2), 3, Complex(real: 4, imaginary: 2)) + testAddition(Complex(real: 1.0, imaginary: 2.0), 3.0, Complex(real: 4.0, imaginary: 2.0)) + testAddition(Complex(real: 1.0, imaginary: 2.0), 3.0, Complex(real: 4.0, imaginary: 2.0)) + testAddition(Complex(real: 1.0, imaginary: 2.0), 3.0, Complex(real: 4.0, imaginary: 2.0)) + testAddition(Complex(real: 1.0, imaginary: 2.0), 3.0, Complex(real: 4.0, imaginary: 2.0)) + } + + func testSubtraction() { + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 2.0, imaginary: 2.0)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 2.0, imaginary: 2.0)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 2.0, imaginary: 2.0)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 2.0, imaginary: 2.0)) + + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3, imaginary: 4), 1, Complex(real: 2, imaginary: 4)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), 1.0, Complex(real: 2.0, imaginary: 4.0)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), 1.0, Complex(real: 2.0, imaginary: 4.0)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), 1.0, Complex(real: 2.0, imaginary: 4.0)) + testSubtraction(Complex(real: 3.0, imaginary: 4.0), 1.0, Complex(real: 2.0, imaginary: 4.0)) + } + + func testMultiplication() { + testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) + testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) + testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) + testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) + testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) + testMultiplication(Complex(real: 4, imaginary: 3), Complex(real: 2, imaginary: 1), Complex(real: 5, imaginary: 10)) + testMultiplication(Complex(real: 4, imaginary: 3), Complex(real: 2, imaginary: 1), Complex(real: 5, imaginary: 10)) + testMultiplication(Complex(real: 4, imaginary: 3), Complex(real: 2, imaginary: 1), Complex(real: 5, imaginary: 10)) + testMultiplication(Complex(real: 4, imaginary: 3), Complex(real: 2, imaginary: 1), Complex(real: 5, imaginary: 10)) + testMultiplication(Complex(real: 4, imaginary: 3), Complex(real: 2, imaginary: 1), Complex(real: 5, imaginary: 10)) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: -5.0, imaginary: 10.0)) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: -5.0, imaginary: 10.0)) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: -5.0, imaginary: 10.0)) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: -5.0, imaginary: 10.0)) + + testMultiplication(Complex(real: 3, imaginary: 4), 2) + testMultiplication(Complex(real: 3, imaginary: 4), 2) + testMultiplication(Complex(real: 3, imaginary: 4), 2) + testMultiplication(Complex(real: 3, imaginary: 4), 2) + testMultiplication(Complex(real: 3, imaginary: 4), 2) + testMultiplication(Complex(real: 4, imaginary: 3), 2) + testMultiplication(Complex(real: 4, imaginary: 3), 2) + testMultiplication(Complex(real: 4, imaginary: 3), 2) + testMultiplication(Complex(real: 4, imaginary: 3), 2) + testMultiplication(Complex(real: 4, imaginary: 3), 2) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), 2.0) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), 2.0) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), 2.0) + testMultiplication(Complex(real: 3.0, imaginary: 4.0), 2.0) + } + + func testDivision() { + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) + testDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 11.0 / 5.0, imaginary: -0.4)) + testDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 11.0 / 5.0, imaginary: -0.4)) + testDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 11.0 / 5.0, imaginary: -0.4)) + testDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0), Complex(real: 11.0 / 5.0, imaginary: -0.4)) + + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3, imaginary: 4), 2) + testDivision(Complex(real: 3.0, imaginary: 4.0), 2.0) + testDivision(Complex(real: 3.0, imaginary: 4.0), 2.0) + testDivision(Complex(real: 3.0, imaginary: 4.0), 2.0) + testDivision(Complex(real: 3.0, imaginary: 4.0), 2.0) + } + + // MARK: Private Methods + + private func testAdditionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(complex, complex + .zero, file: file, line: line) + XCTAssertEqual(complex, complex + Scalar.zero, file: file, line: line) + XCTAssertEqual(complex, Scalar.zero + complex, file: file, line: line) + + var result = complex + result += .zero + XCTAssertEqual(result, complex, file: file, line: line) + + result = complex + XCTAssertEqual(result, complex, file: file, line: line) + + result = complex + result += Scalar.zero + XCTAssertEqual(result, complex, file: file, line: line) + } + + private func testSubtractionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(complex, complex - .zero, file: file, line: line) + XCTAssertEqual(complex, complex - Scalar.zero, file: file, line: line) + + var result = complex + result -= .zero + XCTAssertEqual(result, complex, file: file, line: line) + + result = complex + result -= Scalar.zero + XCTAssertEqual(result, complex, file: file, line: line) + } + + private func testMultiplicationWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(.zero, complex * .zero, file: file, line: line) + XCTAssertEqual(.zero, complex * Scalar.zero, file: file, line: line) + XCTAssertEqual(.zero, Scalar.zero * complex, file: file, line: line) + + var result = complex + result *= .zero + XCTAssertEqual(result, .zero, file: file, line: line) + + result = complex + result *= Scalar.zero + XCTAssertEqual(result, .zero, file: file, line: line) + } + + private func testAddition(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs + rhs, result, file: file, line: line) + XCTAssertEqual(rhs + lhs, result, file: file, line: line) + + var complex = lhs + complex += rhs + XCTAssertEqual(complex, result, file: file, line: line) + + complex = rhs + complex += lhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testAddition(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs + rhs, result, file: file, line: line) + XCTAssertEqual(rhs + lhs, result, file: file, line: line) + + var complex = lhs + complex += rhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs - rhs, result, file: file, line: line) + + var complex = lhs + complex -= rhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { + XCTAssertEqual(lhs - rhs, result, file: file, line: line) + XCTAssertEqual(rhs - lhs, -result, file: file, line: line) + + var complex = lhs + complex -= rhs + XCTAssertEqual(complex, result, file: file, line: line) + + complex = rhs + complex -= lhs + XCTAssertEqual(complex, -result, file: file, line: line) + } + + private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs - rhs, result, file: file, line: line) + + var complex = lhs + complex -= rhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { + XCTAssertEqual(lhs - rhs, result, file: file, line: line) + XCTAssertEqual(rhs - lhs, -result, file: file, line: line) + + var complex = lhs + complex -= rhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testMultiplication(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(lhs * rhs, result, file: file, line: line) + XCTAssertEqual(rhs * lhs, result, file: file, line: line) + + var complex = lhs + complex *= rhs + XCTAssertEqual(complex, result, file: file, line: line) + + complex = rhs + complex *= lhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testMultiplication(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) { + let result = Complex(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs) + XCTAssertEqual(lhs * rhs, result, file: file, line: line) + XCTAssertEqual(rhs * lhs, result, file: file, line: line) + + var complex = lhs + complex *= rhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { + XCTAssertEqual(lhs / rhs, result, file: file, line: line) + + var complex = lhs + complex /= rhs + XCTAssertEqual(complex, result, file: file, line: line) + } + + private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { + XCTAssertTrue((lhs / rhs - result).modulus < 0.0001, file: file, line: line) + + var complex = lhs + complex /= rhs + XCTAssertTrue((complex - result).modulus < 0.0001, file: file, line: line) + } + + private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { + XCTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + + var complex = lhs + complex /= rhs + XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + } + + private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: SignedInteger { + XCTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + XCTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) + + var complex = lhs + complex /= rhs + XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + } + + private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { + XCTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + XCTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) + + var complex = lhs + complex /= rhs + XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + } +} diff --git a/Tests/ComplexTests/ComplexTests.swift b/Tests/ComplexTests/ComplexTests.swift index e23fc9a..5580a75 100644 --- a/Tests/ComplexTests/ComplexTests.swift +++ b/Tests/ComplexTests/ComplexTests.swift @@ -13,172 +13,148 @@ class ComplexTests: XCTestCase { // MARK: Test Methods - func testComplexInitialization() { - do { - var complex = Complex(real: -1.0, imaginary: 2.5) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - - complex = Complex(real: Float(-1.0), imaginary: Float(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - - complex = Complex(real: Double(-1.0), imaginary: Double(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - complex = Complex(real: Float80(-1.0), imaginary: Float80(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - - complex = Complex(real: Int(-4), imaginary: Int(67)) - XCTAssertEqual(complex.real, -4.0) - XCTAssertEqual(complex.imaginary, 67.0) - - complex = Complex(Complex(real: 9.0, imaginary: 4.0)) - XCTAssertEqual(complex.real, 9.0) - XCTAssertEqual(complex.imaginary, 4.0) - - complex = [] - XCTAssertEqual(complex.real, 0.0) - XCTAssertEqual(complex.imaginary, 0.0) - - complex = [-1.0] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 0.0) - - complex = [-1.0, 2.5] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - } - do { - var complex = Complex(real: -1.0, imaginary: 2.5) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - - complex = Complex(real: Half(-1.0), imaginary: Half(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - - complex = Complex(real: Double(-1.0), imaginary: Double(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - complex = Complex(real: Float80(-1.0), imaginary: Float80(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - - complex = Complex(real: Int(-4), imaginary: Int(67)) - XCTAssertEqual(complex.real, -4.0) - XCTAssertEqual(complex.imaginary, 67.0) - - complex = Complex(Complex(real: 9.0, imaginary: 4.0)) - XCTAssertEqual(complex.real, 9.0) - XCTAssertEqual(complex.imaginary, 4.0) - - complex = [] - XCTAssertEqual(complex.real, 0.0) - XCTAssertEqual(complex.imaginary, 0.0) - - complex = [-1.0] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 0.0) - - complex = [-1.0, 2.5] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - } - do { - var complex = Complex(real: -1.0, imaginary: 2.5) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - - complex = Complex(real: Half(-1.0), imaginary: Half(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - - complex = Complex(real: Float(-1.0), imaginary: Float(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - complex = Complex(real: Float80(-1.0), imaginary: Float80(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - - complex = Complex(real: Int(-4), imaginary: Int(67)) - XCTAssertEqual(complex.real, -4.0) - XCTAssertEqual(complex.imaginary, 67.0) - - complex = Complex(Complex(real: 9.0, imaginary: 4.0)) - XCTAssertEqual(complex.real, 9.0) - XCTAssertEqual(complex.imaginary, 4.0) - - complex = [] - XCTAssertEqual(complex.real, 0.0) - XCTAssertEqual(complex.imaginary, 0.0) - - complex = [-1.0] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 0.0) - - complex = [-1.0, 2.5] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - var complex = Complex(real: -1.0, imaginary: 2.5) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) + func testInitialization() { + testInitialization(real: Int8(1), imaginary: Int8(-4)) + testInitialization(real: Int16(1), imaginary: Int16(-4)) + testInitialization(real: Int32(1), imaginary: Int32(-4)) + testInitialization(real: Int64(1), imaginary: Int64(-4)) + testInitialization(real: UInt8(7), imaginary: UInt8(13)) + testInitialization(real: UInt16(7), imaginary: UInt16(13)) + testInitialization(real: UInt32(7), imaginary: UInt32(13)) + testInitialization(real: UInt64(7), imaginary: UInt64(13)) + testInitialization(real: Half(1.2), imaginary: Half(-7.4)) + testInitialization(real: Float(-0.123), imaginary: Float(3.0)) + testInitialization(real: Double(8.9), imaginary: Double(10.8)) + testInitialization(real: Float80(11.1), imaginary: Float80(-0.9)) + } + + func testRandomFactoryMethods() { + testRandomFactoryMethods(lowerBound: Int8(-4), upperBound: Int8(8)) + testRandomFactoryMethods(lowerBound: Int16(-4), upperBound: Int16(8)) + testRandomFactoryMethods(lowerBound: Int32(-4), upperBound: Int32(8)) + testRandomFactoryMethods(lowerBound: Int64(-4), upperBound: Int64(8)) + testRandomFactoryMethods(lowerBound: UInt8(7), upperBound: UInt8(43)) + testRandomFactoryMethods(lowerBound: UInt16(7), upperBound: UInt16(43)) + testRandomFactoryMethods(lowerBound: UInt32(7), upperBound: UInt32(43)) + testRandomFactoryMethods(lowerBound: UInt64(7), upperBound: UInt64(43)) + testRandomFactoryMethods(lowerBound: Half(-1.2), upperBound: Half(7.4)) + testRandomFactoryMethods(lowerBound: Float(-0.123), upperBound: Float(3.0)) + testRandomFactoryMethods(lowerBound: Double(8.9), upperBound: Double(10.8)) + testRandomFactoryMethods(lowerBound: Float80(-11.1), upperBound: Float80(0.9)) + } - complex = Complex(real: Half(-1.0), imaginary: Half(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) + func testDescriptionMethods() throws { + try testDescriptionMethods(Complex(real: Int8(1), imaginary: Int8(-4))) + try testDescriptionMethods(Complex(real: Int16(1), imaginary: Int16(-4))) + try testDescriptionMethods(Complex(real: Int32(1), imaginary: Int32(-4))) + try testDescriptionMethods(Complex(real: Int64(1), imaginary: Int64(-4))) + try testDescriptionMethods(Complex(real: UInt8(7), imaginary: UInt8(13))) + try testDescriptionMethods(Complex(real: UInt16(7), imaginary: UInt16(13))) + try testDescriptionMethods(Complex(real: UInt32(7), imaginary: UInt32(13))) + try testDescriptionMethods(Complex(real: UInt64(7), imaginary: UInt64(13))) + try testDescriptionMethods(Complex(real: Half(1.2), imaginary: Half(-7.4))) + try testDescriptionMethods(Complex(real: Float(-0.123), imaginary: Float(3.0))) + try testDescriptionMethods(Complex(real: Double(8.9), imaginary: Double(10.8))) + try testDescriptionMethods(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } + + func testHashing() { + testHashing(Complex(real: Int8(1), imaginary: Int8(-4))) + testHashing(Complex(real: Int16(1), imaginary: Int16(-4))) + testHashing(Complex(real: Int32(1), imaginary: Int32(-4))) + testHashing(Complex(real: Int64(1), imaginary: Int64(-4))) + testHashing(Complex(real: UInt8(7), imaginary: UInt8(13))) + testHashing(Complex(real: UInt16(7), imaginary: UInt16(13))) + testHashing(Complex(real: UInt32(7), imaginary: UInt32(13))) + testHashing(Complex(real: UInt64(7), imaginary: UInt64(13))) + testHashing(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testHashing(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testHashing(Complex(real: Double(8.9), imaginary: Double(10.8))) + testHashing(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } - complex = Complex(real: Float(-1.0), imaginary: Float(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) + func testRounding() { + testRounding(Complex(real: 1.5, imaginary: -4.5)) + testRounding(Complex(real: 1.5, imaginary: -4.5)) + testRounding(Complex(real: 1.5, imaginary: -4.5)) + testRounding(Complex(real: 1.5, imaginary: -4.5)) + } - complex = Complex(real: Double(-1.0), imaginary: Double(2.5)) - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) + func testConjugateMethods() { + testConjugateMethods(Complex(real: Int8(1), imaginary: Int8(-4))) + testConjugateMethods(Complex(real: Int16(1), imaginary: Int16(-4))) + testConjugateMethods(Complex(real: Int32(1), imaginary: Int32(-4))) + testConjugateMethods(Complex(real: Int64(1), imaginary: Int64(-4))) + testConjugateMethods(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testConjugateMethods(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testConjugateMethods(Complex(real: Double(8.9), imaginary: Double(10.8))) + testConjugateMethods(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } - complex = Complex(real: Int(-4), imaginary: Int(67)) - XCTAssertEqual(complex.real, -4.0) - XCTAssertEqual(complex.imaginary, 67.0) + func testNegationMethods() { + testNegationMethods(Complex(real: Int8(1), imaginary: Int8(-4))) + testNegationMethods(Complex(real: Int16(1), imaginary: Int16(-4))) + testNegationMethods(Complex(real: Int32(1), imaginary: Int32(-4))) + testNegationMethods(Complex(real: Int64(1), imaginary: Int64(-4))) + testNegationMethods(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testNegationMethods(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testNegationMethods(Complex(real: Double(8.9), imaginary: Double(10.8))) + testNegationMethods(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } - complex = Complex(Complex(real: 9.0, imaginary: 4.0)) - XCTAssertEqual(complex.real, 9.0) - XCTAssertEqual(complex.imaginary, 4.0) + func testMultiplyByOne() { + testMultiplyByOne(Complex(real: Int8(1), imaginary: Int8(-4))) + testMultiplyByOne(Complex(real: Int16(1), imaginary: Int16(-4))) + testMultiplyByOne(Complex(real: Int32(1), imaginary: Int32(-4))) + testMultiplyByOne(Complex(real: Int64(1), imaginary: Int64(-4))) + testMultiplyByOne(Complex(real: UInt8(7), imaginary: UInt8(13))) + testMultiplyByOne(Complex(real: UInt16(7), imaginary: UInt16(13))) + testMultiplyByOne(Complex(real: UInt32(7), imaginary: UInt32(13))) + testMultiplyByOne(Complex(real: UInt64(7), imaginary: UInt64(13))) + testMultiplyByOne(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testMultiplyByOne(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testMultiplyByOne(Complex(real: Double(8.9), imaginary: Double(10.8))) + testMultiplyByOne(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } - complex = [] - XCTAssertEqual(complex.real, 0.0) - XCTAssertEqual(complex.imaginary, 0.0) + func testMultiplyByI() { + testMultiplyByI(Complex(real: Int8(1), imaginary: Int8(-4))) + testMultiplyByI(Complex(real: Int16(1), imaginary: Int16(-4))) + testMultiplyByI(Complex(real: Int32(1), imaginary: Int32(-4))) + testMultiplyByI(Complex(real: Int64(1), imaginary: Int64(-4))) + testMultiplyByI(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testMultiplyByI(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testMultiplyByI(Complex(real: Double(8.9), imaginary: Double(10.8))) + testMultiplyByI(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } - complex = [-1.0] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 0.0) + func testPlusPrefixOperator() { + testPlusPrefixOperator(Complex(real: Int8(1), imaginary: Int8(-4))) + testPlusPrefixOperator(Complex(real: Int16(1), imaginary: Int16(-4))) + testPlusPrefixOperator(Complex(real: Int32(1), imaginary: Int32(-4))) + testPlusPrefixOperator(Complex(real: Int64(1), imaginary: Int64(-4))) + testPlusPrefixOperator(Complex(real: UInt8(7), imaginary: UInt8(13))) + testPlusPrefixOperator(Complex(real: UInt16(7), imaginary: UInt16(13))) + testPlusPrefixOperator(Complex(real: UInt32(7), imaginary: UInt32(13))) + testPlusPrefixOperator(Complex(real: UInt64(7), imaginary: UInt64(13))) + testPlusPrefixOperator(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testPlusPrefixOperator(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testPlusPrefixOperator(Complex(real: Double(8.9), imaginary: Double(10.8))) + testPlusPrefixOperator(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) + } - complex = [-1.0, 2.5] - XCTAssertEqual(complex.real, -1.0) - XCTAssertEqual(complex.imaginary, 2.5) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + func testPolarComponents() { + testPolarComponents(Complex(real: Half(1.2), imaginary: Half(-7.4))) + testPolarComponents(Complex(real: Float(-0.123), imaginary: Float(3.0))) + testPolarComponents(Complex(real: Double(8.9), imaginary: Double(10.8))) + testPolarComponents(Complex(real: Float80(11.1), imaginary: Float80(-0.9))) } func testAdditiveArithmeticProtocolRequirements() { XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) do { let lhs = Complex(real: 1.0, imaginary: 2.0) @@ -231,7 +207,6 @@ class ComplexTests: XCTestCase { XCTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) XCTAssertEqual(value, lhs - rhs) } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) do { let lhs = Complex(real: 1.0, imaginary: 2.0) let rhs = Complex(real: 3.0, imaginary: 4.0) @@ -249,624 +224,262 @@ class ComplexTests: XCTestCase { XCTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) XCTAssertEqual(value, lhs - rhs) } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } - func testCustomStrings() { - let half = Complex(real: 1.0, imaginary: 2.0) - _ = half.description - _ = half.debugDescription - _ = half.string(withNotation: .square) - _ = half.string(withNotation: .trigonometric) - _ = half.string(withNotation: .euler) - _ = half.string(withNotation: .angle) - - let float = Complex(real: 1.0, imaginary: 2.0) - _ = float.description - _ = float.debugDescription - _ = float.string(withNotation: .square) - _ = float.string(withNotation: .trigonometric) - _ = float.string(withNotation: .euler) - _ = float.string(withNotation: .angle) - - let double = Complex(real: 1.0, imaginary: 2.0) - _ = double.description - _ = double.debugDescription - _ = double.string(withNotation: .square) - _ = double.string(withNotation: .trigonometric) - _ = double.string(withNotation: .euler) - _ = double.string(withNotation: .angle) - -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - let float80 = Complex(real: 1.0, imaginary: 2.0) - _ = float80.description - _ = float80.debugDescription - _ = float80.string(withNotation: .square) - _ = float80.string(withNotation: .trigonometric) - _ = float80.string(withNotation: .euler) - _ = float80.string(withNotation: .angle) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - } + // MARK: Private Methods - func testHashing() { - let half = Complex(real: 1.0, imaginary: 2.0) - var hasher = Hasher() - hasher.combine(half) - _ = hasher.finalize() + private func testInitialization(real: Scalar, imaginary: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { + let complex0 = Complex() + XCTAssertEqual(complex0.real, 0, file: file, line: line) + XCTAssertEqual(complex0.imaginary, 0, file: file, line: line) - let float = Complex(real: 1.0, imaginary: 2.0) - hasher = Hasher() - hasher.combine(float) - _ = hasher.finalize() + let complex1 = Complex(real: real, imaginary: imaginary) + XCTAssertEqual(complex1.real, real, file: file, line: line) + XCTAssertEqual(complex1.imaginary, imaginary, file: file, line: line) - let double = Complex(real: 1.0, imaginary: 2.0) - hasher = Hasher() - hasher.combine(double) - _ = hasher.finalize() + let complex2 = Complex(complex1) + XCTAssertEqual(complex2.real, real, file: file, line: line) + XCTAssertEqual(complex2.imaginary, imaginary, file: file, line: line) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - let float80 = Complex(real: 1.0, imaginary: 2.0) - hasher = Hasher() - hasher.combine(float80) - _ = hasher.finalize() -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + let complex3 = Complex(real: real, imaginary: imaginary) + XCTAssertEqual(complex3.real, Int64(real), file: file, line: line) + XCTAssertEqual(complex3.imaginary, Int64(imaginary), file: file, line: line) + + let complex4 = Complex(complex1) + XCTAssertEqual(complex4.real, Int64(real), file: file, line: line) + XCTAssertEqual(complex4.imaginary, Int64(imaginary), file: file, line: line) + + let complex5 = Complex(real: real, imaginary: imaginary) + XCTAssertEqual(complex5.real, Float80(real), file: file, line: line) + XCTAssertEqual(complex5.imaginary, Float80(imaginary), file: file, line: line) + + let complex6 = Complex(complex1) + XCTAssertEqual(complex6.real, Float80(real), file: file, line: line) + XCTAssertEqual(complex6.imaginary, Float80(imaginary), file: file, line: line) + + let complex7: Complex = [] + XCTAssertEqual(complex7.real, 0, file: file, line: line) + XCTAssertEqual(complex7.imaginary, 0, file: file, line: line) + + let complex8: Complex = [real] + XCTAssertEqual(complex8.real, real, file: file, line: line) + XCTAssertEqual(complex8.imaginary, 0, file: file, line: line) + + let complex9: Complex = [real, imaginary] + XCTAssertEqual(complex9.real, real, file: file, line: line) + XCTAssertEqual(complex9.imaginary, imaginary, file: file, line: line) } - func testMultiplicationAndDivision() { - do { - let lhs = Complex(real: 3.0, imaginary: 2.0) - let rhs = Complex(real: 1.0, imaginary: 7.0) - var value = lhs - value *= rhs + private func testInitialization(real: Scalar, imaginary: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { + let complex0 = Complex() + XCTAssertEqual(complex0.real, 0.0, file: file, line: line) + XCTAssertEqual(complex0.imaginary, 0.0, file: file, line: line) - XCTAssertEqual(lhs * rhs, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, lhs * rhs) + let complex1 = Complex(real: real, imaginary: imaginary) + XCTAssertEqual(complex1.real, real, file: file, line: line) + XCTAssertEqual(complex1.imaginary, imaginary, file: file, line: line) - value = lhs - value /= rhs + let complex2 = Complex(complex1) + XCTAssertEqual(complex2.real, real, file: file, line: line) + XCTAssertEqual(complex2.imaginary, imaginary, file: file, line: line) - XCTAssertEqual(lhs / rhs, Complex(real: 0.34, imaginary: -0.38)) - XCTAssertEqual(value, Complex(real: 0.34, imaginary: -0.38)) - XCTAssertEqual(value, lhs / rhs) - } - do { - let lhs = Complex(real: 3.0, imaginary: 2.0) - let rhs = Complex(real: 1.0, imaginary: 7.0) - var value = lhs - value *= rhs + let complex3 = Complex(real: real, imaginary: imaginary) + XCTAssertEqual(complex3.real, Int64(real), file: file, line: line) + XCTAssertEqual(complex3.imaginary, Int64(imaginary), file: file, line: line) - XCTAssertEqual(lhs * rhs, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, lhs * rhs) + let complex4 = Complex(complex1) + XCTAssertEqual(complex4.real, Int64(real), file: file, line: line) + XCTAssertEqual(complex4.imaginary, Int64(imaginary), file: file, line: line) - value = lhs - value /= rhs + let complex5 = Complex(real: real, imaginary: imaginary) + XCTAssertEqual(complex5.real, Float80(real), file: file, line: line) + XCTAssertEqual(complex5.imaginary, Float80(imaginary), file: file, line: line) - XCTAssertEqual(lhs / rhs, Complex(real: 0.34, imaginary: -0.38)) - XCTAssertEqual(value, Complex(real: 0.34, imaginary: -0.38)) - XCTAssertEqual(value, lhs / rhs) - } - do { - let lhs = Complex(real: 3.0, imaginary: 2.0) - let rhs = Complex(real: 1.0, imaginary: 7.0) - var value = lhs - value *= rhs + let complex6 = Complex(complex1) + XCTAssertEqual(complex6.real, Float80(real), file: file, line: line) + XCTAssertEqual(complex6.imaginary, Float80(imaginary), file: file, line: line) - XCTAssertEqual(lhs * rhs, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, lhs * rhs) + let complex7: Complex = [] + XCTAssertEqual(complex7.real, 0.0, file: file, line: line) + XCTAssertEqual(complex7.imaginary, 0.0, file: file, line: line) - value = lhs - value /= rhs + let complex8: Complex = [real] + XCTAssertEqual(complex8.real, real, file: file, line: line) + XCTAssertEqual(complex8.imaginary, 0.0, file: file, line: line) - XCTAssertEqual(lhs / rhs, Complex(real: 0.34, imaginary: -0.38)) - XCTAssertEqual(value, Complex(real: 0.34, imaginary: -0.38)) - XCTAssertEqual(value, lhs / rhs) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - let lhs = Complex(real: 3.0, imaginary: 2.0) - let rhs = Complex(real: 1.0, imaginary: 7.0) - var value = lhs - value *= rhs + let complex9: Complex = [real, imaginary] + XCTAssertEqual(complex9.real, real, file: file, line: line) + XCTAssertEqual(complex9.imaginary, imaginary, file: file, line: line) + } - XCTAssertEqual(lhs * rhs, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, Complex(real: -11.0, imaginary: 23.0)) - XCTAssertEqual(value, lhs * rhs) + private func testRandomFactoryMethods(lowerBound: Scalar, upperBound: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + var generator = SystemRandomNumberGenerator() + let closedRange: ClosedRange = lowerBound ... upperBound + let range: Range = lowerBound ..< upperBound - value = lhs - value /= rhs + let complex1 = Complex.random(in: range) + XCTAssertTrue(range.contains(complex1.real), file: file, line: line) + XCTAssertTrue(range.contains(complex1.imaginary), file: file, line: line) - XCTAssertTrue(((lhs / rhs) - Complex(real: 0.34, imaginary: -0.38)).modulus < 0.0001) - XCTAssertTrue((value - Complex(real: 0.34, imaginary: -0.38)).modulus < 0.0001) - XCTAssertEqual(value, lhs / rhs) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + let complex2 = Complex.random(in: range, using: &generator) + XCTAssertTrue(range.contains(complex2.real), file: file, line: line) + XCTAssertTrue(range.contains(complex2.imaginary), file: file, line: line) + + let complex3 = Complex.random(in: closedRange) + XCTAssertTrue(closedRange.contains(complex3.real), file: file, line: line) + XCTAssertTrue(closedRange.contains(complex3.imaginary), file: file, line: line) + + let complex4 = Complex.random(in: closedRange, using: &generator) + XCTAssertTrue(closedRange.contains(complex4.real), file: file, line: line) + XCTAssertTrue(closedRange.contains(complex4.imaginary), file: file, line: line) } - func testComplexArithmeticWithRealNumbers() { - do { - let complex = Complex(real: 3.0, imaginary: 2.0) - let real: Half = 5.0 - var value = complex - value += real - - XCTAssertEqual(complex + real, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(real + complex, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, complex + real) - XCTAssertEqual(value, real + complex) - - value = complex - value -= real - - XCTAssertEqual(complex - real, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(real - complex, Complex(real: 2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(value, complex - real) - XCTAssertEqual(-value, real - complex) - - value = complex - value *= real - - XCTAssertEqual(complex * real, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(real * complex, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, complex * real) - XCTAssertEqual(value, real * complex) - - value = complex - value /= real - - XCTAssertEqual(complex / real, Complex(real: 0.6, imaginary: 0.4)) - XCTAssertEqual(real / complex, Complex(real: 1.1542969, imaginary: -0.76904297)) - XCTAssertEqual(value, Complex(real: 0.6, imaginary: 0.4)) - XCTAssertEqual(value, complex / real) - } - do { - let complex = Complex(real: 3.0, imaginary: 2.0) - let real: Float = 5.0 - var value = complex - value += real - - XCTAssertEqual(complex + real, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(real + complex, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, complex + real) - XCTAssertEqual(value, real + complex) - - value = complex - value -= real - - XCTAssertEqual(complex - real, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(real - complex, Complex(real: 2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(value, complex - real) - XCTAssertEqual(-value, real - complex) - - value = complex - value *= real - - XCTAssertEqual(complex * real, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(real * complex, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, complex * real) - XCTAssertEqual(value, real * complex) - - value = complex - value /= real - - XCTAssertEqual(complex / real, Complex(real: 0.6, imaginary: 0.4)) - XCTAssertTrue(((real / complex) - Complex(real: 1.1542969, imaginary: -0.76904297)).modulus < 0.001) - XCTAssertEqual(value, Complex(real: 0.6, imaginary: 0.4)) - XCTAssertEqual(value, complex / real) - } - do { - let complex = Complex(real: 3.0, imaginary: 2.0) - let real: Double = 5.0 - var value = complex - value += real - - XCTAssertEqual(complex + real, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(real + complex, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, complex + real) - XCTAssertEqual(value, real + complex) - - value = complex - value -= real - - XCTAssertEqual(complex - real, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(real - complex, Complex(real: 2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(value, complex - real) - XCTAssertEqual(-value, real - complex) - - value = complex - value *= real - - XCTAssertEqual(complex * real, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(real * complex, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, complex * real) - XCTAssertEqual(value, real * complex) - - value = complex - value /= real - - XCTAssertEqual(complex / real, Complex(real: 0.6, imaginary: 0.4)) - XCTAssertTrue(((real / complex) - Complex(real: 1.1542969, imaginary: -0.76904297)).modulus < 0.001) - XCTAssertEqual(value, Complex(real: 0.6, imaginary: 0.4)) - XCTAssertEqual(value, complex / real) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - let complex = Complex(real: 3.0, imaginary: 2.0) - let real: Float80 = 5.0 - var value = complex - value += real - - XCTAssertEqual(complex + real, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(real + complex, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, Complex(real: 8.0, imaginary: 2.0)) - XCTAssertEqual(value, complex + real) - XCTAssertEqual(value, real + complex) - - value = complex - value -= real - - XCTAssertEqual(complex - real, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(real - complex, Complex(real: 2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: 2.0)) - XCTAssertEqual(value, complex - real) - XCTAssertEqual(-value, real - complex) - - value = complex - value *= real - - XCTAssertEqual(complex * real, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(real * complex, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, Complex(real: 15.0, imaginary: 10.0)) - XCTAssertEqual(value, complex * real) - XCTAssertEqual(value, real * complex) - - value = complex - value /= real - - XCTAssertTrue(((complex / real) - Complex(real: 0.6, imaginary: 0.4)).modulus < 0.001) - XCTAssertTrue(((real / complex) - Complex(real: 1.1542969, imaginary: -0.76904297)).modulus < 0.001) - XCTAssertTrue((value - Complex(real: 0.6, imaginary: 0.4)).modulus < 0.001) - XCTAssertEqual(value, complex / real) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + private func testRandomFactoryMethods(lowerBound: Scalar, upperBound: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint, Scalar.RawSignificand: FixedWidthInteger { + var generator = SystemRandomNumberGenerator() + let closedRange: ClosedRange = lowerBound ... upperBound + let range: Range = lowerBound ..< upperBound + + let complex1 = Complex.random(in: range) + XCTAssertTrue(range.contains(complex1.real), file: file, line: line) + XCTAssertTrue(range.contains(complex1.imaginary), file: file, line: line) + + let complex2 = Complex.random(in: range, using: &generator) + XCTAssertTrue(range.contains(complex2.real), file: file, line: line) + XCTAssertTrue(range.contains(complex2.imaginary), file: file, line: line) + + let complex3 = Complex.random(in: closedRange) + XCTAssertTrue(closedRange.contains(complex3.real), file: file, line: line) + XCTAssertTrue(closedRange.contains(complex3.imaginary), file: file, line: line) + + let complex4 = Complex.random(in: closedRange, using: &generator) + XCTAssertTrue(closedRange.contains(complex4.real), file: file, line: line) + XCTAssertTrue(closedRange.contains(complex4.imaginary), file: file, line: line) } - func testNegation() { - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + private func testDescriptionMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) throws where Scalar: BinaryInteger { + let description = complex.description + let debugDescription = complex.debugDescription - complex.negate() - XCTAssertEqual(complex.real, 7.0) - XCTAssertEqual(complex.imaginary, -4.0) + let realRegex = try NSRegularExpression(pattern: "real:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.real)"))", options: []) + let imaginaryRegex = try NSRegularExpression(pattern: "imaginary:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.imaginary)"))", options: []) - complex = -complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertEqual(description, debugDescription, file: file, line: line) + XCTAssertTrue(realRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) + XCTAssertTrue(imaginaryRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) - complex = +complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) - } - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.real)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.imaginary)"), file: file, line: line) - complex.negate() - XCTAssertEqual(complex.real, 7.0) - XCTAssertEqual(complex.imaginary, -4.0) + XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.modulus)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.angle)"), file: file, line: line) - complex = -complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.modulus)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.angle)"), file: file, line: line) - complex = +complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) - } - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.modulus)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.angle)"), file: file, line: line) + } - complex.negate() - XCTAssertEqual(complex.real, 7.0) - XCTAssertEqual(complex.imaginary, -4.0) + private func testDescriptionMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) throws where Scalar: BinaryFloatingPoint { + let description = complex.description + let debugDescription = complex.debugDescription - complex = -complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + let realRegex = try NSRegularExpression(pattern: "real:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.real)"))", options: []) + let imaginaryRegex = try NSRegularExpression(pattern: "imaginary:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.imaginary)"))", options: []) - complex = +complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertEqual(description, debugDescription, file: file, line: line) + XCTAssertTrue(realRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) + XCTAssertTrue(imaginaryRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) - complex.negate() - XCTAssertEqual(complex.real, 7.0) - XCTAssertEqual(complex.imaginary, -4.0) + XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.real)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.imaginary)"), file: file, line: line) - complex = -complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.modulus)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.angle)"), file: file, line: line) - complex = +complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.modulus)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.angle)"), file: file, line: line) + + XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.modulus)"), file: file, line: line) + XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.angle)"), file: file, line: line) } - func testConjugates() { - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + private func testHashing(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: Hashable { + var hasher = Hasher() + hasher.combine(complex) + let value1 = hasher.finalize() - complex.formConjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) + hasher = Hasher() + hasher.combine(complex.real) + hasher.combine(complex.imaginary) + let value2 = hasher.finalize() - complex = complex.conjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + XCTAssertEqual(value1, value2, file: file, line: line) + } - complex = ~complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) - } - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + private func testRounding(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: FloatingPoint { + XCTAssertEqual(complex.rounded(), Complex(real: complex.real.rounded(), imaginary: complex.imaginary.rounded()), file: file, line: line) - complex.formConjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) + var rounded = complex + rounded.round() + XCTAssertEqual(rounded, complex.rounded(), file: file, line: line) - complex = complex.conjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + for rule in [FloatingPointRoundingRule.toNearestOrAwayFromZero, .toNearestOrEven, .up, .down, .towardZero, .awayFromZero] { + XCTAssertEqual(complex.rounded(rule), Complex(real: complex.real.rounded(rule), imaginary: complex.imaginary.rounded(rule)), file: file, line: line) - complex = ~complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) + var rounded = complex + rounded.round(rule) + XCTAssertEqual(rounded, complex.rounded(rule), file: file, line: line) } - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + } - complex.formConjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) + private func testConjugateMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { + var conjugate = complex.conjugate() + XCTAssertEqual(complex.real, conjugate.real, file: file, line: line) + XCTAssertEqual(complex.imaginary, -conjugate.imaginary, file: file, line: line) - complex = complex.conjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + conjugate = ~complex + XCTAssertEqual(complex.real, conjugate.real, file: file, line: line) + XCTAssertEqual(complex.imaginary, -conjugate.imaginary, file: file, line: line) - complex = ~complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - var complex = Complex(real: -7.0, imaginary: 4.0) - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + conjugate = complex + conjugate.formConjugate() + XCTAssertEqual(complex.real, conjugate.real, file: file, line: line) + XCTAssertEqual(complex.imaginary, -conjugate.imaginary, file: file, line: line) + } - complex.formConjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) + private func testNegationMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { + var negative = -complex + XCTAssertEqual(complex.real, -negative.real, file: file, line: line) + XCTAssertEqual(complex.imaginary, -negative.imaginary, file: file, line: line) - complex = complex.conjugate() - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, 4.0) + negative = complex + negative.negate() + XCTAssertEqual(complex.real, -negative.real, file: file, line: line) + XCTAssertEqual(complex.imaginary, -negative.imaginary, file: file, line: line) + } - complex = ~complex - XCTAssertEqual(complex.real, -7.0) - XCTAssertEqual(complex.imaginary, -4.0) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + private func testMultiplyByOne(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { + let one = Complex.one + let result = complex * one + + XCTAssertEqual(result, complex, file: file, line: line) } - func testRounding() { - do { - let complex = Complex(real: 1.5, imaginary: -4.5) - XCTAssertEqual(complex.rounded(), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrAwayFromZero), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrEven), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.up), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.down), Complex(real: 1.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.towardZero), Complex(real: 1.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.awayFromZero), Complex(real: 2.0, imaginary: -5.0)) - - var value = complex - value.round() - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrAwayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrEven) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.up) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.down) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -5.0)) - - value = complex - value.round(.towardZero) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -4.0)) - - value = complex - value.round(.awayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - } - do { - let complex = Complex(real: 1.5, imaginary: -4.5) - XCTAssertEqual(complex.rounded(), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrAwayFromZero), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrEven), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.up), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.down), Complex(real: 1.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.towardZero), Complex(real: 1.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.awayFromZero), Complex(real: 2.0, imaginary: -5.0)) - - var value = complex - value.round() - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrAwayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrEven) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.up) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.down) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -5.0)) - - value = complex - value.round(.towardZero) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -4.0)) - - value = complex - value.round(.awayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - } - do { - let complex = Complex(real: 1.5, imaginary: -4.5) - XCTAssertEqual(complex.rounded(), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrAwayFromZero), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrEven), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.up), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.down), Complex(real: 1.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.towardZero), Complex(real: 1.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.awayFromZero), Complex(real: 2.0, imaginary: -5.0)) - - var value = complex - value.round() - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrAwayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrEven) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.up) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.down) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -5.0)) - - value = complex - value.round(.towardZero) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -4.0)) - - value = complex - value.round(.awayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - let complex = Complex(real: 1.5, imaginary: -4.5) - XCTAssertEqual(complex.rounded(), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrAwayFromZero), Complex(real: 2.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.toNearestOrEven), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.up), Complex(real: 2.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.down), Complex(real: 1.0, imaginary: -5.0)) - XCTAssertEqual(complex.rounded(.towardZero), Complex(real: 1.0, imaginary: -4.0)) - XCTAssertEqual(complex.rounded(.awayFromZero), Complex(real: 2.0, imaginary: -5.0)) - - var value = complex - value.round() - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrAwayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - - value = complex - value.round(.toNearestOrEven) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.up) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -4.0)) - - value = complex - value.round(.down) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -5.0)) - - value = complex - value.round(.towardZero) - XCTAssertEqual(value, Complex(real: 1.0, imaginary: -4.0)) - - value = complex - value.round(.awayFromZero) - XCTAssertEqual(value, Complex(real: 2.0, imaginary: -5.0)) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + private func testMultiplyByI(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { + let i = Complex.i + let result = complex * i + + XCTAssertEqual(result.real, -complex.imaginary, file: file, line: line) + XCTAssertEqual(result.imaginary, complex.real, file: file, line: line) } - func testPolarComponents() { - do { - let complex = Complex(real: 3.0, imaginary: 4.0) - XCTAssertEqual(complex.modulus, 5.0) - XCTAssertEqual(complex.angle, 0.9272461) - } - do { - let complex = Complex(real: 3.0, imaginary: 4.0) - XCTAssertEqual(complex.modulus, 5.0) - XCTAssertEqual(complex.angle, 0.9272952) - } - do { - let complex = Complex(real: 3.0, imaginary: 4.0) - XCTAssertEqual(complex.modulus, 5.0) - XCTAssertEqual(complex.angle, 0.9272952180016122) - } -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - do { - let complex = Complex(real: 3.0, imaginary: 4.0) - XCTAssertEqual(complex.modulus, 5.0) - XCTAssertEqual(complex.angle, 0.9272952180016122324) - } -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) + private func testPlusPrefixOperator(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { + XCTAssertEqual(complex, +complex, file: file, line: line) + } + + private func testPolarComponents(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { + XCTAssertEqual(complex.modulus, sqrt(complex.real * complex.real + complex.imaginary * complex.imaginary), file: file, line: line) + XCTAssertEqual(complex.angle, Scalar(atan2(Float80(complex.imaginary), Float80(complex.real))), file: file, line: line) } } diff --git a/Tests/ComplexTests/FunctionsTests.swift b/Tests/ComplexTests/FunctionsTests.swift index 9732da9..8749a02 100644 --- a/Tests/ComplexTests/FunctionsTests.swift +++ b/Tests/ComplexTests/FunctionsTests.swift @@ -23,10 +23,8 @@ class FunctionsTests: XCTestCase { XCTAssertEqual(csqrt(Double(-4.0)), Complex(real: 0.0, imaginary: 2.0)) XCTAssertEqual(csqrt(Double(9.0)), Complex(real: 3.0, imaginary: 0.0)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(csqrt(Float80(-4.0)), Complex(real: 0.0, imaginary: 2.0)) XCTAssertEqual(csqrt(Float80(9.0)), Complex(real: 3.0, imaginary: 0.0)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } func test_sqrt() { @@ -51,41 +49,33 @@ class FunctionsTests: XCTestCase { XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: -4.0)) - Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())).modulus < 0.0001) XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: 4.0)) - Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())).modulus < 0.0001) XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } func test_abs() { XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } func test_min() { XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } func test_max() { XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } func test_clamp() { @@ -97,9 +87,7 @@ class FunctionsTests: XCTestCase { XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) -#if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) -#endif // #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) } } From cbde4be2015adf6cbdbff849b7df58aeeee1f2e3 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Thu, 20 Feb 2020 10:13:13 -0500 Subject: [PATCH 02/13] Added additional primitive functions for floating point complex numbers --- .gitignore | 1 + ATTRIBUTIONS | 216 ++++ Complex.xcodeproj/project.pbxproj | 132 ++ Sources/Complex/Functions.swift | 236 ++++ Sources/Complex/Functions.swift.gyb | 193 +++ Tests/ComplexTests/FunctionsTests.swift | 173 +++ Tests/ComplexTests/FunctionsTests.swift.gyb | 212 ++++ utils/gyb | 3 + utils/gyb.py | 1260 +++++++++++++++++++ 9 files changed, 2426 insertions(+) create mode 100644 ATTRIBUTIONS create mode 100644 Sources/Complex/Functions.swift.gyb create mode 100644 Tests/ComplexTests/FunctionsTests.swift.gyb create mode 100755 utils/gyb create mode 100644 utils/gyb.py diff --git a/.gitignore b/.gitignore index e9bbc3c..a500584 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ Complex.xcodeproj/project.xcworkspace Complex.xcodeproj/xcuserdata .swiftpm Carthage +gyb.pyc diff --git a/ATTRIBUTIONS b/ATTRIBUTIONS new file mode 100644 index 0000000..545b330 --- /dev/null +++ b/ATTRIBUTIONS @@ -0,0 +1,216 @@ +gyb and gyb.py are copied from the Swift project. + +https://github.com/apple/swift +-------------------------------------------------- + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +## Runtime Library Exception to the Apache 2.0 License: ## + + + As an exception, if you use this Software to compile your source code and + portions of this Software are embedded into the binary product as a result, + you may redistribute such product without providing attribution as would + otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. diff --git a/Complex.xcodeproj/project.pbxproj b/Complex.xcodeproj/project.pbxproj index dd8fccd..f37fa14 100644 --- a/Complex.xcodeproj/project.pbxproj +++ b/Complex.xcodeproj/project.pbxproj @@ -7,6 +7,17 @@ objects = { /* Begin PBXAggregateTarget section */ + DDB8127223FA5C0C0079FEB5 /* Generate Sources */ = { + isa = PBXAggregateTarget; + buildConfigurationList = DDB8127323FA5C0C0079FEB5 /* Build configuration list for PBXAggregateTarget "Generate Sources" */; + buildPhases = ( + DDB8127623FA5C160079FEB5 /* Generate Sources */, + ); + dependencies = ( + ); + name = "Generate Sources"; + productName = "Generate Sources"; + }; DDFEECA423F1BA0B0096015C /* Run SwiftLint */ = { isa = PBXAggregateTarget; buildConfigurationList = DDFEECA523F1BA0B0096015C /* Build configuration list for PBXAggregateTarget "Run SwiftLint" */; @@ -51,6 +62,20 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + DDB8127723FA5C380079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDB8127223FA5C0C0079FEB5; + remoteInfo = "Generate Sources"; + }; + DDB8127923FA5C3E0079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDB8127223FA5C0C0079FEB5; + remoteInfo = "Generate Sources"; + }; DDB8127B23FA5C3E0079FEB5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DDFEEC2A23EF13900096015C /* Project object */; @@ -58,6 +83,13 @@ remoteGlobalIDString = DDFEECA423F1BA0B0096015C; remoteInfo = "Run SwiftLint"; }; + DDB8127D23FA5C430079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDB8127223FA5C0C0079FEB5; + remoteInfo = "Generate Sources"; + }; DDB8127F23FA5C430079FEB5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DDFEEC2A23EF13900096015C /* Project object */; @@ -65,6 +97,13 @@ remoteGlobalIDString = DDFEECA423F1BA0B0096015C; remoteInfo = "Run SwiftLint"; }; + DDB8128123FA5C480079FEB5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DDFEEC2A23EF13900096015C /* Project object */; + proxyType = 1; + remoteGlobalIDString = DDB8127223FA5C0C0079FEB5; + remoteInfo = "Generate Sources"; + }; DDB8128323FA5C480079FEB5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DDFEEC2A23EF13900096015C /* Project object */; @@ -113,6 +152,11 @@ DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionsTests.swift; sourceTree = ""; }; DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexArithmetic.swift; sourceTree = ""; }; DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexArithmeticTests.swift; sourceTree = ""; }; + DDB8126B23FA2B950079FEB5 /* gyb.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gyb.py; sourceTree = ""; }; + DDB8126C23FA2B950079FEB5 /* gyb */ = {isa = PBXFileReference; lastKnownFileType = text; path = gyb; sourceTree = ""; }; + DDB8126F23FA2C210079FEB5 /* Functions.swift.gyb */ = {isa = PBXFileReference; explicitFileType = text.script.python; path = Functions.swift.gyb; sourceTree = ""; }; + DDB8127123FA4DA50079FEB5 /* ATTRIBUTIONS */ = {isa = PBXFileReference; lastKnownFileType = text; path = ATTRIBUTIONS; sourceTree = ""; }; + DDB8128523FB1A430079FEB5 /* FunctionsTests.swift.gyb */ = {isa = PBXFileReference; explicitFileType = text.script.python; path = FunctionsTests.swift.gyb; sourceTree = ""; }; DDFEEC3323EF13900096015C /* Complex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Complex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; DDFEEC3723EF13900096015C /* Complex-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "Complex-Info.plist"; path = "Info/Complex-Info.plist"; sourceTree = ""; }; DDFEEC3C23EF13910096015C /* ComplexTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ComplexTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -207,6 +251,15 @@ name = Frameworks; sourceTree = ""; }; + DDB8126A23FA2B810079FEB5 /* Utils */ = { + isa = PBXGroup; + children = ( + DDB8126C23FA2B950079FEB5 /* gyb */, + DDB8126B23FA2B950079FEB5 /* gyb.py */, + ); + path = Utils; + sourceTree = ""; + }; DDFEEC2923EF13900096015C = { isa = PBXGroup; children = ( @@ -236,6 +289,7 @@ DDFEEC8E23F0B9F90096015C /* Sources */, DDFEECAA23F1BA280096015C /* Supporting Files */, DD94FBF723F3C50E0041D4EC /* Tests */, + DDB8126A23FA2B810079FEB5 /* Utils */, ); name = Complex; sourceTree = ""; @@ -246,6 +300,7 @@ DDB8121023F5AEB10079FEB5 /* ComplexTests.swift */, DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */, DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */, + DDB8128523FB1A430079FEB5 /* FunctionsTests.swift.gyb */, DDFEEC4323EF13910096015C /* ComplexTests-Info.plist */, ); path = ComplexTests; @@ -268,6 +323,7 @@ DDFEECAE23F1BA5E0096015C /* .swiftlint.yml */, DDFEECAD23F1BA5E0096015C /* .travis.yml */, DDFEECAF23F1BA680096015C /* README.md */, + DDB8127123FA4DA50079FEB5 /* ATTRIBUTIONS */, DDFEECB123F1BA730096015C /* LICENSE */, DDFEEC3723EF13900096015C /* Complex-Info.plist */, ); @@ -279,6 +335,7 @@ children = ( DDB8120623F59B760079FEB5 /* Complex.swift */, DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */, + DDB8126F23FA2C210079FEB5 /* Functions.swift.gyb */, DDB8120B23F5A8E80079FEB5 /* Functions.swift */, ); path = Complex; @@ -330,6 +387,7 @@ buildRules = ( ); dependencies = ( + DDB8127823FA5C380079FEB5 /* PBXTargetDependency */, DDFEECB323F1BB5B0096015C /* PBXTargetDependency */, ); name = Complex; @@ -367,6 +425,7 @@ buildRules = ( ); dependencies = ( + DDB8127A23FA5C3E0079FEB5 /* PBXTargetDependency */, DDB8127C23FA5C3E0079FEB5 /* PBXTargetDependency */, ); name = "Complex macOS"; @@ -404,6 +463,7 @@ buildRules = ( ); dependencies = ( + DDB8127E23FA5C430079FEB5 /* PBXTargetDependency */, DDB8128023FA5C430079FEB5 /* PBXTargetDependency */, ); name = "Complex tvOS"; @@ -441,6 +501,7 @@ buildRules = ( ); dependencies = ( + DDB8128223FA5C480079FEB5 /* PBXTargetDependency */, DDB8128423FA5C480079FEB5 /* PBXTargetDependency */, ); name = "Complex watchOS"; @@ -458,6 +519,9 @@ LastUpgradeCheck = 1130; ORGANIZATIONNAME = SomeRandomiOSDev; TargetAttributes = { + DDB8127223FA5C0C0079FEB5 = { + CreatedOnToolsVersion = 11.3.1; + }; DDFEEC3223EF13900096015C = { CreatedOnToolsVersion = 11.3.1; LastSwiftMigration = 1130; @@ -511,6 +575,7 @@ DDFEECD923F2003E0096015C /* Complex tvOS */, DDFEECE123F2003E0096015C /* Complex tvOS Tests */, DDFEECF523F2004D0096015C /* Complex watchOS */, + DDB8127223FA5C0C0079FEB5 /* Generate Sources */, DDFEECA423F1BA0B0096015C /* Run SwiftLint */, ); }; @@ -569,6 +634,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + DDB8127623FA5C160079FEB5 /* Generate Sources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Sources/Complex/Functions.swift.gyb", + "$(SRCROOT)/Tests/ComplexTests/FunctionsTests.swift.gyb", + ); + name = "Generate Sources"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(SRCROOT)/Sources/Complex/Functions.swift", + "$(SRCROOT)/Tests/ComplexTests/FunctionsTests.swift", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "./utils/gyb --line-directive '' -o ./Sources/Complex/Functions.swift ./Sources/Complex/Functions.swift.gyb\n./utils/gyb --line-directive '' -o ./Tests/ComplexTests/FunctionsTests.swift ./Tests/ComplexTests/FunctionsTests.swift.gyb\n"; + }; DDFEECA923F1BA160096015C /* Run SwiftLint */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -663,16 +750,36 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + DDB8127823FA5C380079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDB8127223FA5C0C0079FEB5 /* Generate Sources */; + targetProxy = DDB8127723FA5C380079FEB5 /* PBXContainerItemProxy */; + }; + DDB8127A23FA5C3E0079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDB8127223FA5C0C0079FEB5 /* Generate Sources */; + targetProxy = DDB8127923FA5C3E0079FEB5 /* PBXContainerItemProxy */; + }; DDB8127C23FA5C3E0079FEB5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DDFEECA423F1BA0B0096015C /* Run SwiftLint */; targetProxy = DDB8127B23FA5C3E0079FEB5 /* PBXContainerItemProxy */; }; + DDB8127E23FA5C430079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDB8127223FA5C0C0079FEB5 /* Generate Sources */; + targetProxy = DDB8127D23FA5C430079FEB5 /* PBXContainerItemProxy */; + }; DDB8128023FA5C430079FEB5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DDFEECA423F1BA0B0096015C /* Run SwiftLint */; targetProxy = DDB8127F23FA5C430079FEB5 /* PBXContainerItemProxy */; }; + DDB8128223FA5C480079FEB5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DDB8127223FA5C0C0079FEB5 /* Generate Sources */; + targetProxy = DDB8128123FA5C480079FEB5 /* PBXContainerItemProxy */; + }; DDB8128423FA5C480079FEB5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DDFEECA423F1BA0B0096015C /* Run SwiftLint */; @@ -701,6 +808,22 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + DDB8127423FA5C0C0079FEB5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + DDB8127523FA5C0C0079FEB5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; DDFEEC4523EF13910096015C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1199,6 +1322,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + DDB8127323FA5C0C0079FEB5 /* Build configuration list for PBXAggregateTarget "Generate Sources" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DDB8127423FA5C0C0079FEB5 /* Debug */, + DDB8127523FA5C0C0079FEB5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DDFEEC2D23EF13900096015C /* Build configuration list for PBXProject "Complex" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/Sources/Complex/Functions.swift b/Sources/Complex/Functions.swift index 6aada0d..3836f34 100644 --- a/Sources/Complex/Functions.swift +++ b/Sources/Complex/Functions.swift @@ -61,3 +61,239 @@ public func clamp(_ value: Complex, _ minimum: F, _ maximum: F) -> Complex public func clamp(_ value: Complex, _ minimum: Complex, _ maximum: Complex) -> Complex where F: Comparable { return Complex(real: max(minimum.real, min(value.real, maximum.real)), imaginary: max(minimum.imaginary, min(value.imaginary, maximum.imaginary))) } + +// +// exp(a + bi) = exp(a) * (cos(b) + i * sin(b)) + +@_transparent +public func exp(_ value: Complex) -> Complex { + let exp = Darwin.exp(value.real) + return Complex(real: exp * cos(value.imaginary), imaginary: exp * sin(value.imaginary)) +} + +@_transparent +public func exp(_ value: Complex) -> Complex { + let exp = Darwin.exp(value.real) + return Complex(real: exp * cos(value.imaginary), imaginary: exp * sin(value.imaginary)) +} + +@_transparent +public func exp(_ value: Complex) -> Complex { + let exp = Darwin.exp(value.real) + return Complex(real: exp * cos(value.imaginary), imaginary: exp * sin(value.imaginary)) +} + +// +// log(a + bi) = log(sqrt(a^2 + b^2)) + i * atan(b / a) + +@_transparent +public func log(_ value: Complex) -> Complex { + return Complex(real: log(value.modulus), imaginary: value.angle) +} + +@_transparent +public func log(_ value: Complex) -> Complex { + return Complex(real: log(value.modulus), imaginary: value.angle) +} + +@_transparent +public func log(_ value: Complex) -> Complex { + return Complex(real: log(value.modulus), imaginary: value.angle) +} + +// + +@_transparent +public func log10(_ value: Complex) -> Complex { + return log(value) / log(10.0) +} + +@_transparent +public func log10(_ value: Complex) -> Complex { + return log(value) / log(10.0) +} + +@_transparent +public func log10(_ value: Complex) -> Complex { + return log(value) / log(10.0) +} + +// + +@_transparent +public func log2(_ value: Complex) -> Complex { + return log(value) / log(2.0) +} + +@_transparent +public func log2(_ value: Complex) -> Complex { + return log(value) / log(2.0) +} + +@_transparent +public func log2(_ value: Complex) -> Complex { + return log(value) / log(2.0) +} + +// +// sin(a + bi) = sin(a) * cosh(b) + i * cos(a) * sinh(b) + +@_transparent +public func sin(_ value: Complex) -> Complex { + return Complex(real: sin(value.real) * cosh(value.imaginary), imaginary: cos(value.real) * sinh(value.imaginary)) +} + +@_transparent +public func sin(_ value: Complex) -> Complex { + return Complex(real: sin(value.real) * cosh(value.imaginary), imaginary: cos(value.real) * sinh(value.imaginary)) +} + +@_transparent +public func sin(_ value: Complex) -> Complex { + return Complex(real: sin(value.real) * cosh(value.imaginary), imaginary: cos(value.real) * sinh(value.imaginary)) +} + +// +// asin(z) = -i * ln(iz + sqrt(1 - z^2)) + +@_transparent +public func asin(_ value: Complex) -> Complex { + return -.i * log(.i * value + sqrt(1.0 - value * value)) +} + +@_transparent +public func asin(_ value: Complex) -> Complex { + return -.i * log(.i * value + sqrt(1.0 - value * value)) +} + +@_transparent +public func asin(_ value: Complex) -> Complex { + return -.i * log(.i * value + sqrt(1.0 - value * value)) +} + +// +// sinh(z) = -i * sin(iz) + +@_transparent +public func sinh(_ value: Complex) -> Complex { + return -.i * sin(.i * value) +} + +@_transparent +public func sinh(_ value: Complex) -> Complex { + return -.i * sin(.i * value) +} + +@_transparent +public func sinh(_ value: Complex) -> Complex { + return -.i * sin(.i * value) +} + +// +// cos(a + bi) = cos(a) * cosh(b) - i * sin(a) * sinh(b) + +@_transparent +public func cos(_ value: Complex) -> Complex { + return Complex(real: cos(value.real) * cosh(value.imaginary), imaginary: -sin(value.real) * sinh(value.imaginary)) +} + +@_transparent +public func cos(_ value: Complex) -> Complex { + return Complex(real: cos(value.real) * cosh(value.imaginary), imaginary: -sin(value.real) * sinh(value.imaginary)) +} + +@_transparent +public func cos(_ value: Complex) -> Complex { + return Complex(real: cos(value.real) * cosh(value.imaginary), imaginary: -sin(value.real) * sinh(value.imaginary)) +} + +// +// acos(z) = -i * ln(z + sqrt(z^2 - 1)) + +@_transparent +public func acos(_ value: Complex) -> Complex { + return -.i * log(value + sqrt(value * value - 1.0)) +} + +@_transparent +public func acos(_ value: Complex) -> Complex { + return -.i * log(value + sqrt(value * value - 1.0)) +} + +@_transparent +public func acos(_ value: Complex) -> Complex { + return -.i * log(value + sqrt(value * value - 1.0)) +} + +// +// cosh(z) = cos(iz) + +@_transparent +public func cosh(_ value: Complex) -> Complex { + return cos(.i * value) +} + +@_transparent +public func cosh(_ value: Complex) -> Complex { + return cos(.i * value) +} + +@_transparent +public func cosh(_ value: Complex) -> Complex { + return cos(.i * value) +} + +// + +@_transparent +public func tan(_ value: Complex) -> Complex { + return sin(value) / cos(value) +} + +@_transparent +public func tan(_ value: Complex) -> Complex { + return sin(value) / cos(value) +} + +@_transparent +public func tan(_ value: Complex) -> Complex { + return sin(value) / cos(value) +} + +// +// atan(z) = (i / 2) * ln((i + z) / (i - z)) + +@_transparent +public func atan(_ value: Complex) -> Complex { + return .i * 0.5 * log((.i + value) / (.i - value)) +} + +@_transparent +public func atan(_ value: Complex) -> Complex { + return .i * 0.5 * log((.i + value) / (.i - value)) +} + +@_transparent +public func atan(_ value: Complex) -> Complex { + return .i * 0.5 * log((.i + value) / (.i - value)) +} + +// +// tanh(z) = -i * tan(iz) + +@_transparent +public func tanh(_ value: Complex) -> Complex { + return -.i * tan(.i * value) +} + +@_transparent +public func tanh(_ value: Complex) -> Complex { + return -.i * tan(.i * value) +} + +@_transparent +public func tanh(_ value: Complex) -> Complex { + return -.i * tan(.i * value) +} + +// diff --git a/Sources/Complex/Functions.swift.gyb b/Sources/Complex/Functions.swift.gyb new file mode 100644 index 0000000..3d1b759 --- /dev/null +++ b/Sources/Complex/Functions.swift.gyb @@ -0,0 +1,193 @@ +// +// Functions.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +import Foundation + +@_transparent +public func csqrt(_ value: F) -> Complex where F: FloatingPoint { + let complex: Complex + if value < 0 { + complex = Complex(real: .zero, imaginary: sqrt(-value)) + } else { + complex = Complex(real: sqrt(value), imaginary: .zero) + } + + return complex +} + +@_transparent +public func sqrt(_ value: Complex) -> Complex where F: FloatingPoint { + //swiftlint:disable opening_brace statement_position + let sign = { (value: F) -> F in + let sign: F + if value < .zero { sign = -1 } + else { sign = 1 } + return sign + } + //swiftlint:enable opening_brace statement_position + + let modulus = value.modulus + let real = sqrt((value.real + modulus) / F(2)) + let imaginary = sign(value.imaginary) * sqrt((modulus - value.real) / F(2)) + + return Complex(real: real, imaginary: imaginary) +} + +@_transparent +public func abs(_ value: Complex) -> Complex where F: Comparable, F: SignedNumeric { + return Complex(real: abs(value.real), imaginary: abs(value.imaginary)) +} + +@_transparent +public func min(_ lhs: Complex, _ rhs: Complex) -> Complex where F: Comparable { + return Complex(real: min(lhs.real, rhs.real), imaginary: min(lhs.imaginary, rhs.imaginary)) +} + +@_transparent +public func max(_ lhs: Complex, _ rhs: Complex) -> Complex where F: Comparable { + return Complex(real: max(lhs.real, rhs.real), imaginary: max(lhs.imaginary, rhs.imaginary)) +} + +@_transparent +public func clamp(_ value: Complex, _ minimum: F, _ maximum: F) -> Complex where F: Comparable { + return Complex(real: max(minimum, min(value.real, maximum)), imaginary: max(minimum, min(value.imaginary, maximum))) +} + +@_transparent +public func clamp(_ value: Complex, _ minimum: Complex, _ maximum: Complex) -> Complex where F: Comparable { + return Complex(real: max(minimum.real, min(value.real, maximum.real)), imaginary: max(minimum.imaginary, min(value.imaginary, maximum.imaginary))) +} + +// +// exp(a + bi) = exp(a) * (cos(b) + i * sin(b)) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func exp(_ value: Complex<${type}>) -> Complex<${type}> { + let exp = Darwin.exp(value.real) + return Complex<${type}>(real: exp * cos(value.imaginary), imaginary: exp * sin(value.imaginary)) +} + +% end +// +// log(a + bi) = log(sqrt(a^2 + b^2)) + i * atan(b / a) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func log(_ value: Complex<${type}>) -> Complex<${type}> { + return Complex<${type}>(real: log(value.modulus), imaginary: value.angle) +} + +% end +// + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func log10(_ value: Complex<${type}>) -> Complex<${type}> { + return log(value) / log(10.0) +} + +% end +// + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func log2(_ value: Complex<${type}>) -> Complex<${type}> { + return log(value) / log(2.0) +} + +% end +// +// sin(a + bi) = sin(a) * cosh(b) + i * cos(a) * sinh(b) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func sin(_ value: Complex<${type}>) -> Complex<${type}> { + return Complex<${type}>(real: sin(value.real) * cosh(value.imaginary), imaginary: cos(value.real) * sinh(value.imaginary)) +} + +% end +// +// asin(z) = -i * ln(iz + sqrt(1 - z^2)) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func asin(_ value: Complex<${type}>) -> Complex<${type}> { + return -.i * log(.i * value + sqrt(1.0 - value * value)) +} + +% end +// +// sinh(z) = -i * sin(iz) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func sinh(_ value: Complex<${type}>) -> Complex<${type}> { + return -.i * sin(.i * value) +} + +% end +// +// cos(a + bi) = cos(a) * cosh(b) - i * sin(a) * sinh(b) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func cos(_ value: Complex<${type}>) -> Complex<${type}> { + return Complex<${type}>(real: cos(value.real) * cosh(value.imaginary), imaginary: -sin(value.real) * sinh(value.imaginary)) +} + +% end +// +// acos(z) = -i * ln(z + sqrt(z^2 - 1)) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func acos(_ value: Complex<${type}>) -> Complex<${type}> { + return -.i * log(value + sqrt(value * value - 1.0)) +} + +% end +// +// cosh(z) = cos(iz) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func cosh(_ value: Complex<${type}>) -> Complex<${type}> { + return cos(.i * value) +} + +% end +// + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func tan(_ value: Complex<${type}>) -> Complex<${type}> { + return sin(value) / cos(value) +} + +% end +// +// atan(z) = (i / 2) * ln((i + z) / (i - z)) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func atan(_ value: Complex<${type}>) -> Complex<${type}> { + return .i * 0.5 * log((.i + value) / (.i - value)) +} + +% end +// +// tanh(z) = -i * tan(iz) + +% for type in ["Float", "Double", "Float80"]: +@_transparent +public func tanh(_ value: Complex<${type}>) -> Complex<${type}> { + return -.i * tan(.i * value) +} + +% end +// diff --git a/Tests/ComplexTests/FunctionsTests.swift b/Tests/ComplexTests/FunctionsTests.swift index 8749a02..b882cd1 100644 --- a/Tests/ComplexTests/FunctionsTests.swift +++ b/Tests/ComplexTests/FunctionsTests.swift @@ -90,4 +90,177 @@ class FunctionsTests: XCTestCase { XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) } + + func test_exp() { + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + } + + func test_log() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + } + } + + func test_log10() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + } + } + + func test_log2() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + } + } + + func test_sin() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + } + + func test_asin() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + } + } + + func test_sinh() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + } + } + + func test_cos() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + } + + func test_acos() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + } + } + + func test_cosh() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + } + } + + func test_tan() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + } + } + + func test_atan() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + } + } + + func test_tanh() { + for complex in sampleComplexNumbers(ofType: Float.self) { + XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Double.self) { + XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + } + for complex in sampleComplexNumbers(ofType: Float80.self) { + XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + } + } + + // MARK: Private Methods + + private func sampleComplexNumbers(ofType: Scalar.Type) -> [Complex] where Scalar: BinaryFloatingPoint { + return [Complex(real: 2.0, imaginary: 0.0), + Complex(real: 2.0, imaginary: .pi * 0.5), + Complex(real: 2.0, imaginary: .pi), + Complex(real: 2.0, imaginary: .pi * 1.5)] + } +} + +func XCTAssertEqual(_ expression1: @autoclosure () throws -> Complex, _ expression2: @autoclosure () throws -> Complex, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) rethrows where T: FloatingPoint { + let difference = try abs(expression1() - expression2()) + XCTAssertTrue(difference.real <= accuracy && difference.imaginary <= accuracy, message(), file: file, line: line) } diff --git a/Tests/ComplexTests/FunctionsTests.swift.gyb b/Tests/ComplexTests/FunctionsTests.swift.gyb new file mode 100644 index 0000000..f7eff13 --- /dev/null +++ b/Tests/ComplexTests/FunctionsTests.swift.gyb @@ -0,0 +1,212 @@ +// +// FunctionsTests.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +@testable import Complex +import Half +import XCTest + +class FunctionsTests: XCTestCase { + + // MARK: Test Methods + + func test_csqrt() { + XCTAssertEqual(csqrt(Half(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(csqrt(Half(9.0)), Complex(real: 3.0, imaginary: 0.0)) + + XCTAssertEqual(csqrt(Float(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(csqrt(Float(9.0)), Complex(real: 3.0, imaginary: 0.0)) + + XCTAssertEqual(csqrt(Double(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(csqrt(Double(9.0)), Complex(real: 3.0, imaginary: 0.0)) + + XCTAssertEqual(csqrt(Float80(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(csqrt(Float80(9.0)), Complex(real: 3.0, imaginary: 0.0)) + } + + func test_sqrt() { + XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: -4.0)) - Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())).modulus < 0.0001) + XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: 4.0)) - Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())).modulus < 0.0001) + XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + } + + func test_abs() { + XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + } + + func test_min() { + XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + } + + func test_max() { + XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + } + + func test_clamp() { + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + } + + func test_exp() { + % for type in ["Float", "Double", "Float80"]: + XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: 0.0)), Complex<${type}>(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi * 0.5)), Complex<${type}>(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi)), Complex<${type}>(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi * 1.5)), Complex<${type}>(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + % end + } + + func test_log() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(log(complex), Complex<${type}>(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + } + % end + } + + func test_log10() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + } + % end + } + + func test_log2() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + } + % end + } + + func test_sin() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(sin(complex), Complex<${type}>(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + % end + } + + func test_asin() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + } + % end + } + + func test_sinh() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + } + % end + } + + func test_cos() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(cos(complex), Complex<${type}>(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + } + % end + } + + func test_acos() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + } + % end + } + + func test_cosh() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + } + % end + } + + func test_tan() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + } + % end + } + + func test_atan() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + } + % end + } + + func test_tanh() { + % for type in ["Float", "Double", "Float80"]: + for complex in sampleComplexNumbers(ofType: ${type}.self) { + XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + } + % end + } + + // MARK: Private Methods + + private func sampleComplexNumbers(ofType: Scalar.Type) -> [Complex] where Scalar: BinaryFloatingPoint { + return [Complex(real: 2.0, imaginary: 0.0), + Complex(real: 2.0, imaginary: .pi * 0.5), + Complex(real: 2.0, imaginary: .pi), + Complex(real: 2.0, imaginary: .pi * 1.5)] + } +} + +func XCTAssertEqual(_ expression1: @autoclosure () throws -> Complex, _ expression2: @autoclosure () throws -> Complex, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) rethrows where T: FloatingPoint { + let difference = try abs(expression1() - expression2()) + XCTAssertTrue(difference.real <= accuracy && difference.imaginary <= accuracy, message(), file: file, line: line) +} diff --git a/utils/gyb b/utils/gyb new file mode 100755 index 0000000..dece788 --- /dev/null +++ b/utils/gyb @@ -0,0 +1,3 @@ +#!/usr/bin/env python2.7 +import gyb +gyb.main() diff --git a/utils/gyb.py b/utils/gyb.py new file mode 100644 index 0000000..2df9a03 --- /dev/null +++ b/utils/gyb.py @@ -0,0 +1,1260 @@ +#!/usr/bin/env python +# GYB: Generate Your Boilerplate (improved names welcome; at least +# this one's short). See -h output for instructions + +from __future__ import print_function + +import os +import re +import sys +import textwrap +import tokenize +from bisect import bisect + + +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + + +try: + basestring +except NameError: + basestring = str + + +def get_line_starts(s): + """Return a list containing the start index of each line in s. + + The list also contains a sentinel index for the end of the string, + so there will be one more element in the list than there are lines + in the string + """ + starts = [0] + + for line in s.split('\n'): + starts.append(starts[-1] + len(line) + 1) + + starts[-1] -= 1 + return starts + + +def strip_trailing_nl(s): + """If s ends with a newline, drop it; else return s intact""" + return s[:-1] if s.endswith('\n') else s + + +def split_lines(s): + """Split s into a list of lines, each of which has a trailing newline + + If the lines are later concatenated, the result is s, possibly + with a single appended newline. + """ + return [l + '\n' for l in s.split('\n')] + + +# text on a line up to the first '$$', '${', or '%%' +literalText = r'(?: [^$\n%] | \$(?![${]) | %(?!%) )*' + +# The part of an '%end' line that follows the '%' sign +linesClose = r'[\ \t]* end [\ \t]* (?: \# .* )? $' + +# Note: Where "# Absorb" appears below, the regexp attempts to eat up +# through the end of ${...} and %{...}% constructs. In reality we +# handle this with the Python tokenizer, which avoids mis-detections +# due to nesting, comments and strings. This extra absorption in the +# regexp facilitates testing the regexp on its own, by preventing the +# interior of some of these constructs from being treated as literal +# text. +tokenize_re = re.compile( + r''' +# %-lines and %{...}-blocks + # \n? # absorb one preceding newline + ^ + (?: + (?P + (?P<_indent> [\ \t]* % (?! [{%] ) [\ \t]* ) (?! [\ \t] | ''' + + linesClose + r''' ) .* + ( \n (?P=_indent) (?! ''' + linesClose + r''' ) .* ) * + ) + | (?P [\ \t]* % [ \t]* ''' + linesClose + r''' ) + | [\ \t]* (?P %\{ ) + (?: [^}]| \} (?!%) )* \}% # Absorb + ) + \n? # absorb one trailing newline + +# Substitutions +| (?P \$\{ ) + [^}]* \} # Absorb + +# %% and $$ are literal % and $ respectively +| (?P[$%]) (?P=symbol) + +# Literal text +| (?P ''' + literalText + r''' + (?: + # newline that doesn't precede space+% + (?: \n (?! [\ \t]* %[^%] ) ) + ''' + literalText + r''' + )* + \n? + ) +''', re.VERBOSE | re.MULTILINE) + +gyb_block_close = re.compile(r'\}%[ \t]*\n?') + + +def token_pos_to_index(token_pos, start, line_starts): + """Translate a tokenize (line, column) pair into an absolute + position in source text given the position where we started + tokenizing and a list that maps lines onto their starting + character indexes. + """ + relative_token_line_plus1, token_col = token_pos + + # line number where we started tokenizing + start_line_num = bisect(line_starts, start) - 1 + + # line number of the token in the whole text + abs_token_line = relative_token_line_plus1 - 1 + start_line_num + + # if found in the first line, adjust the end column to account + # for the extra text + if relative_token_line_plus1 == 1: + token_col += start - line_starts[start_line_num] + + # Sometimes tokenizer errors report a line beyond the last one + if abs_token_line >= len(line_starts): + return line_starts[-1] + + return line_starts[abs_token_line] + token_col + + +def tokenize_python_to_unmatched_close_curly(source_text, start, line_starts): + """Apply Python's tokenize to source_text starting at index start + while matching open and close curly braces. When an unmatched + close curly brace is found, return its index. If not found, + return len(source_text). If there's a tokenization error, return + the position of the error. + """ + stream = StringIO(source_text) + stream.seek(start) + nesting = 0 + + try: + for kind, text, token_start, token_end, line_text \ + in tokenize.generate_tokens(stream.readline): + + if text == '{': + nesting += 1 + elif text == '}': + nesting -= 1 + if nesting < 0: + return token_pos_to_index(token_start, start, line_starts) + + except tokenize.TokenError as error: + (message, error_pos) = error.args + return token_pos_to_index(error_pos, start, line_starts) + + return len(source_text) + + +def tokenize_template(template_text): + r"""Given the text of a template, returns an iterator over + (tokenType, token, match) tuples. + + **Note**: this is template syntax tokenization, not Python + tokenization. + + When a non-literal token is matched, a client may call + iter.send(pos) on the iterator to reset the position in + template_text at which scanning will resume. + + This function provides a base level of tokenization which is + then refined by ParseContext.token_generator. + + >>> from pprint import * + >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( + ... '%for x in range(10):\n% print x\n%end\njuicebox'))) + [('gybLines', '%for x in range(10):\n% print x'), + ('gybLinesClose', '%end'), + ('literal', 'juicebox')] + + >>> pprint(list((kind, text) for kind, text, _ in tokenize_template( + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... '''))) + [('literal', 'Nothing\n'), + ('gybLines', '% if x:\n% for i in range(3):'), + ('substitutionOpen', '${'), + ('literal', '\n'), + ('gybLinesClose', '% end'), + ('gybLines', '% else:'), + ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n')] + + >>> for kind, text, _ in tokenize_template(''' + ... This is $some$ literal stuff containing a ${substitution} + ... followed by a %{...} block: + ... %{ + ... # Python code + ... }% + ... and here $${are} some %-lines: + ... % x = 1 + ... % y = 2 + ... % if z == 3: + ... % print '${hello}' + ... % end + ... % for x in zz: + ... % print x + ... % # different indentation + ... % twice + ... and some lines that literally start with a %% token + ... %% first line + ... %% second line + ... '''): + ... print((kind, text.strip().split('\n',1)[0])) + ('literal', 'This is $some$ literal stuff containing a') + ('substitutionOpen', '${') + ('literal', 'followed by a %{...} block:') + ('gybBlockOpen', '%{') + ('literal', 'and here ${are} some %-lines:') + ('gybLines', '% x = 1') + ('gybLinesClose', '% end') + ('gybLines', '% for x in zz:') + ('gybLines', '% # different indentation') + ('gybLines', '% twice') + ('literal', 'and some lines that literally start with a % token') + """ + pos = 0 + end = len(template_text) + + saved_literal = [] + literal_first_match = None + + while pos < end: + m = tokenize_re.match(template_text, pos, end) + + # pull out the one matched key (ignoring internal patterns starting + # with _) + ((kind, text), ) = ( + (kind, text) for (kind, text) in m.groupdict().items() + if text is not None and kind[0] != '_') + + if kind in ('literal', 'symbol'): + if len(saved_literal) == 0: + literal_first_match = m + # literals and symbols get batched together + saved_literal.append(text) + pos = None + else: + # found a non-literal. First yield any literal we've accumulated + if saved_literal != []: + yield 'literal', ''.join(saved_literal), literal_first_match + saved_literal = [] + + # Then yield the thing we found. If we get a reply, it's + # the place to resume tokenizing + pos = yield kind, text, m + + # If we were not sent a new position by our client, resume + # tokenizing at the end of this match. + if pos is None: + pos = m.end(0) + else: + # Client is not yet ready to process next token + yield + + if saved_literal != []: + yield 'literal', ''.join(saved_literal), literal_first_match + + +def split_gyb_lines(source_lines): + r"""Return a list of lines at which to split the incoming source + + These positions represent the beginnings of python line groups that + will require a matching %end construct if they are to be closed. + + >>> src = split_lines('''\ + ... if x: + ... print x + ... if y: # trailing comment + ... print z + ... if z: # another comment\ + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 2 + >>> src[s[0]] + ' print z\n' + >>> s[1] - len(src) + 0 + + >>> src = split_lines('''\ + ... if x: + ... if y: print 1 + ... if z: + ... print 2 + ... pass\ + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 1 + >>> src[s[0]] + ' if y: print 1\n' + + >>> src = split_lines('''\ + ... if x: + ... if y: + ... print 1 + ... print 2 + ... ''') + >>> s = split_gyb_lines(src) + >>> len(s) + 2 + >>> src[s[0]] + ' if y:\n' + >>> src[s[1]] + ' print 1\n' + """ + last_token_text, last_token_kind = None, None + unmatched_indents = [] + + dedents = 0 + try: + for token_kind, token_text, token_start, \ + (token_end_line, token_end_col), line_text \ + in tokenize.generate_tokens(lambda i=iter(source_lines): + next(i)): + + if token_kind in (tokenize.COMMENT, tokenize.ENDMARKER): + continue + + if token_text == '\n' and last_token_text == ':': + unmatched_indents.append(token_end_line) + + # The tokenizer appends dedents at EOF; don't consider + # those as matching indentations. Instead just save them + # up... + if last_token_kind == tokenize.DEDENT: + dedents += 1 + # And count them later, when we see something real. + if token_kind != tokenize.DEDENT and dedents > 0: + unmatched_indents = unmatched_indents[:-dedents] + dedents = 0 + + last_token_text, last_token_kind = token_text, token_kind + + except tokenize.TokenError: + # Let the later compile() call report the error + return [] + + if last_token_text == ':': + unmatched_indents.append(len(source_lines)) + + return unmatched_indents + + +def code_starts_with_dedent_keyword(source_lines): + r"""Return True iff the incoming Python source_lines begin with "else", + "elif", "except", or "finally". + + Initial comments and whitespace are ignored. + + >>> code_starts_with_dedent_keyword(split_lines('if x in y: pass')) + False + >>> code_starts_with_dedent_keyword(split_lines('except ifSomethingElse:')) + True + >>> code_starts_with_dedent_keyword( + ... split_lines('\n# comment\nelse: # yes')) + True + """ + token_text = None + for token_kind, token_text, _, _, _ \ + in tokenize.generate_tokens(lambda i=iter(source_lines): next(i)): + + if token_kind != tokenize.COMMENT and token_text.strip() != '': + break + + return token_text in ('else', 'elif', 'except', 'finally') + + +class ParseContext(object): + + """State carried through a parse of a template""" + + filename = '' + template = '' + line_starts = [] + code_start_line = -1 + code_text = None + tokens = None # The rest of the tokens + close_lines = False + + def __init__(self, filename, template=None): + self.filename = os.path.abspath(filename) + if sys.platform == 'win32': + self.filename = self.filename.replace('\\', '/') + if template is None: + with open(filename) as f: + self.template = f.read() + else: + self.template = template + self.line_starts = get_line_starts(self.template) + self.tokens = self.token_generator(tokenize_template(self.template)) + self.next_token() + + def pos_to_line(self, pos): + return bisect(self.line_starts, pos) - 1 + + def token_generator(self, base_tokens): + r"""Given an iterator over (kind, text, match) triples (see + tokenize_template above), return a refined iterator over + token_kinds. + + Among other adjustments to the elements found by base_tokens, + this refined iterator tokenizes python code embedded in + template text to help determine its true extent. The + expression "base_tokens.send(pos)" is used to reset the index at + which base_tokens resumes scanning the underlying text. + + >>> ctx = ParseContext('dummy', ''' + ... %for x in y: + ... % print x + ... % end + ... literally + ... ''') + >>> while ctx.token_kind: + ... print((ctx.token_kind, ctx.code_text or ctx.token_text)) + ... ignored = ctx.next_token() + ('literal', '\n') + ('gybLinesOpen', 'for x in y:\n') + ('gybLines', ' print x\n') + ('gybLinesClose', '% end') + ('literal', 'literally\n') + + >>> ctx = ParseContext('dummy', + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + >>> while ctx.token_kind: + ... print((ctx.token_kind, ctx.code_text or ctx.token_text)) + ... ignored = ctx.next_token() + ('literal', 'Nothing\n') + ('gybLinesOpen', 'if x:\n') + ('gybLinesOpen', ' for i in range(3):\n') + ('substitutionOpen', 'i') + ('literal', '\n') + ('gybLinesClose', '% end') + ('gybLinesOpen', 'else:\n') + ('literal', 'THIS SHOULD NOT APPEAR IN THE OUTPUT\n') + + >>> ctx = ParseContext('dummy', + ... '''% for x in [1, 2, 3]: + ... % if x == 1: + ... literal1 + ... % elif x > 1: # add output line here to fix bug + ... % if x == 2: + ... literal2 + ... % end + ... % end + ... % end + ... ''') + >>> while ctx.token_kind: + ... print((ctx.token_kind, ctx.code_text or ctx.token_text)) + ... ignored = ctx.next_token() + ('gybLinesOpen', 'for x in [1, 2, 3]:\n') + ('gybLinesOpen', ' if x == 1:\n') + ('literal', 'literal1\n') + ('gybLinesOpen', 'elif x > 1: # add output line here to fix bug\n') + ('gybLinesOpen', ' if x == 2:\n') + ('literal', 'literal2\n') + ('gybLinesClose', '% end') + ('gybLinesClose', '% end') + ('gybLinesClose', '% end') + """ + for self.token_kind, self.token_text, self.token_match in base_tokens: + kind = self.token_kind + self.code_text = None + + # Do we need to close the current lines? + self.close_lines = kind == 'gybLinesClose' + + # %{...}% and ${...} constructs + if kind.endswith('Open'): + + # Tokenize text that follows as Python up to an unmatched '}' + code_start = self.token_match.end(kind) + self.code_start_line = self.pos_to_line(code_start) + + close_pos = tokenize_python_to_unmatched_close_curly( + self.template, code_start, self.line_starts) + self.code_text = self.template[code_start:close_pos] + yield kind + + if (kind == 'gybBlockOpen'): + # Absorb any '}% \n' + m2 = gyb_block_close.match(self.template, close_pos) + if not m2: + raise ValueError("Invalid block closure") + next_pos = m2.end(0) + else: + assert kind == 'substitutionOpen' + # skip past the closing '}' + next_pos = close_pos + 1 + + # Resume tokenizing after the end of the code. + base_tokens.send(next_pos) + + elif kind == 'gybLines': + + self.code_start_line = self.pos_to_line( + self.token_match.start('gybLines')) + indentation = self.token_match.group('_indent') + + # Strip off the leading indentation and %-sign + source_lines = re.split( + '^' + re.escape(indentation), + self.token_match.group('gybLines') + '\n', + flags=re.MULTILINE)[1:] + + if code_starts_with_dedent_keyword(source_lines): + self.close_lines = True + + last_split = 0 + for line in split_gyb_lines(source_lines): + self.token_kind = 'gybLinesOpen' + self.code_text = ''.join(source_lines[last_split:line]) + yield self.token_kind + last_split = line + self.code_start_line += line - last_split + self.close_lines = False + + self.code_text = ''.join(source_lines[last_split:]) + if self.code_text: + self.token_kind = 'gybLines' + yield self.token_kind + else: + yield self.token_kind + + def next_token(self): + """Move to the next token""" + for kind in self.tokens: + return self.token_kind + + self.token_kind = None + + +_default_line_directive = \ + '// ###sourceLocation(file: "%(file)s", line: %(line)d)' + + +class ExecutionContext(object): + + """State we pass around during execution of a template""" + + def __init__(self, line_directive=_default_line_directive, + **local_bindings): + self.local_bindings = local_bindings + self.line_directive = line_directive + self.local_bindings['__context__'] = self + self.result_text = [] + self.last_file_line = None + + def append_text(self, text, file, line): + # see if we need to inject a line marker + if self.line_directive: + if (file, line) != self.last_file_line: + # We can only insert the line directive at a line break + if len(self.result_text) == 0 \ + or self.result_text[-1].endswith('\n'): + substitutions = {'file': file, 'line': line + 1} + format_str = self.line_directive + '\n' + self.result_text.append(format_str % substitutions) + # But if the new text contains any line breaks, we can create + # one + elif '\n' in text: + i = text.find('\n') + self.result_text.append(text[:i + 1]) + # and try again + self.append_text(text[i + 1:], file, line + 1) + return + + self.result_text.append(text) + self.last_file_line = (file, line + text.count('\n')) + + +class ASTNode(object): + + """Abstract base class for template AST nodes""" + + def __init__(self): + raise NotImplementedError("ASTNode.__init__ is not implemented.") + + def execute(self, context): + raise NotImplementedError("ASTNode.execute is not implemented.") + + def __str__(self, indent=''): + raise NotImplementedError("ASTNode.__str__ is not implemented.") + + def format_children(self, indent): + if not self.children: + return ' []' + + return '\n'.join( + ['', indent + '['] + + [x.__str__(indent + 4 * ' ') for x in self.children] + + [indent + ']']) + + +class Block(ASTNode): + + """A sequence of other AST nodes, to be executed in order""" + + children = [] + + def __init__(self, context): + self.children = [] + + while context.token_kind and not context.close_lines: + if context.token_kind == 'literal': + node = Literal + else: + node = Code + self.children.append(node(context)) + + def execute(self, context): + for x in self.children: + x.execute(context) + + def __str__(self, indent=''): + return indent + 'Block:' + self.format_children(indent) + + +class Literal(ASTNode): + + """An AST node that generates literal text""" + + def __init__(self, context): + self.text = context.token_text + start_position = context.token_match.start(context.token_kind) + self.start_line_number = context.pos_to_line(start_position) + self.filename = context.filename + context.next_token() + + def execute(self, context): + context.append_text(self.text, self.filename, self.start_line_number) + + def __str__(self, indent=''): + return '\n'.join( + [indent + x for x in ['Literal:'] + + strip_trailing_nl(self.text).split('\n')]) + + +class Code(ASTNode): + + """An AST node that is evaluated as Python""" + + code = None + children = () + kind = None + + def __init__(self, context): + + source = '' + source_line_count = 0 + + def accumulate_code(): + s = source + (context.code_start_line - source_line_count) * '\n' \ + + textwrap.dedent(context.code_text) + line_count = context.code_start_line + \ + context.code_text.count('\n') + context.next_token() + return s, line_count + + eval_exec = 'exec' + if context.token_kind.startswith('substitution'): + eval_exec = 'eval' + source, source_line_count = accumulate_code() + source = '(' + source.strip() + ')' + + else: + while context.token_kind == 'gybLinesOpen': + source, source_line_count = accumulate_code() + source += ' __children__[%d].execute(__context__)\n' % len( + self.children) + source_line_count += 1 + + self.children += (Block(context),) + + if context.token_kind == 'gybLinesClose': + context.next_token() + + if context.token_kind == 'gybLines': + source, source_line_count = accumulate_code() + + # Only handle a substitution as part of this code block if + # we don't already have some %-lines. + elif context.token_kind == 'gybBlockOpen': + + # Opening ${...} and %{...}% constructs + source, source_line_count = accumulate_code() + + self.filename = context.filename + self.start_line_number = context.code_start_line + self.code = compile(source, context.filename, eval_exec) + self.source = source + + def execute(self, context): + # Save __children__ from the local bindings + save_children = context.local_bindings.get('__children__') + # Execute the code with our __children__ in scope + context.local_bindings['__children__'] = self.children + context.local_bindings['__file__'] = self.filename + result = eval(self.code, context.local_bindings) + + if context.local_bindings['__children__'] is not self.children: + raise ValueError("The code is not allowed to mutate __children__") + # Restore the bindings + context.local_bindings['__children__'] = save_children + + # If we got a result, the code was an expression, so append + # its value + if result is not None \ + or (isinstance(result, basestring) and result != ''): + from numbers import Number, Integral + result_string = None + if isinstance(result, Number) and not isinstance(result, Integral): + result_string = repr(result) + else: + result_string = str(result) + context.append_text( + result_string, self.filename, self.start_line_number) + + def __str__(self, indent=''): + source_lines = re.sub(r'^\n', '', strip_trailing_nl( + self.source), flags=re.MULTILINE).split('\n') + if len(source_lines) == 1: + s = indent + 'Code: {' + source_lines[0] + '}' + else: + s = indent + 'Code:\n' + indent + '{\n' + '\n'.join( + indent + 4 * ' ' + l for l in source_lines + ) + '\n' + indent + '}' + return s + self.format_children(indent) + + +def expand(filename, line_directive=_default_line_directive, **local_bindings): + r"""Return the contents of the given template file, executed with the given + local bindings. + + >>> from tempfile import NamedTemporaryFile + >>> # On Windows, the name of a NamedTemporaryFile cannot be used to open + >>> # the file for a second time if delete=True. Therefore, we have to + >>> # manually handle closing and deleting this file to allow us to open + >>> # the file by its name across all platforms. + >>> f = NamedTemporaryFile(delete=False) + >>> f.write( + ... r'''--- + ... % for i in range(int(x)): + ... a pox on ${i} for epoxy + ... % end + ... ${120 + + ... + ... 3} + ... abc + ... ${"w\nx\nX\ny"} + ... z + ... ''') + >>> f.flush() + >>> result = expand( + ... f.name, + ... line_directive='//#sourceLocation(file: "%(file)s", ' + \ + ... 'line: %(line)d)', + ... x=2 + ... ).replace( + ... '"%s"' % f.name.replace('\\', '/'), '"dummy.file"') + >>> print(result, end='') + //#sourceLocation(file: "dummy.file", line: 1) + --- + //#sourceLocation(file: "dummy.file", line: 3) + a pox on 0 for epoxy + //#sourceLocation(file: "dummy.file", line: 3) + a pox on 1 for epoxy + //#sourceLocation(file: "dummy.file", line: 5) + 123 + //#sourceLocation(file: "dummy.file", line: 8) + abc + w + x + X + y + //#sourceLocation(file: "dummy.file", line: 10) + z + >>> f.close() + >>> os.remove(f.name) + """ + with open(filename) as f: + t = parse_template(filename, f.read()) + d = os.getcwd() + os.chdir(os.path.dirname(os.path.abspath(filename))) + try: + return execute_template( + t, line_directive=line_directive, **local_bindings) + finally: + os.chdir(d) + + +def parse_template(filename, text=None): + r"""Return an AST corresponding to the given template file. + + If text is supplied, it is assumed to be the contents of the file, + as a string. + + >>> print(parse_template('dummy.file', text= + ... '''% for x in [1, 2, 3]: + ... % if x == 1: + ... literal1 + ... % elif x > 1: # add output line after this line to fix bug + ... % if x == 2: + ... literal2 + ... % end + ... % end + ... % end + ... ''')) + Block: + [ + Code: + { + for x in [1, 2, 3]: + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: + { + if x == 1: + __children__[0].execute(__context__) + elif x > 1: # add output line after this line to fix bug + __children__[1].execute(__context__) + } + [ + Block: + [ + Literal: + literal1 + ] + Block: + [ + Code: + { + if x == 2: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + literal2 + ] + ] + ] + ] + ] + ] + ] + + >>> print(parse_template( + ... 'dummy.file', + ... text='%for x in range(10):\n% print(x)\n%end\njuicebox')) + Block: + [ + Code: + { + for x in range(10): + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {print(x)} [] + ] + ] + Literal: + juicebox + ] + + >>> print(parse_template('/dummy.file', text= + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''')) + Block: + [ + Literal: + Nothing + Code: + { + if x: + __children__[0].execute(__context__) + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: + { + for i in range(3): + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {(i)} [] + Literal: + + ] + ] + ] + Block: + [ + Literal: + THIS SHOULD NOT APPEAR IN THE OUTPUT + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''% + ... %for x in y: + ... % print(y) + ... ''')) + Block: + [ + Code: + { + for x in y: + __children__[0].execute(__context__) + } + [ + Block: + [ + Code: {print(y)} [] + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''% + ... %if x: + ... % print(y) + ... AAAA + ... %else: + ... BBBB + ... ''')) + Block: + [ + Code: + { + if x: + __children__[0].execute(__context__) + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: {print(y)} [] + Literal: + AAAA + ] + Block: + [ + Literal: + BBBB + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''% + ... %if x: + ... % print(y) + ... AAAA + ... %# This is a comment + ... %else: + ... BBBB + ... ''')) + Block: + [ + Code: + { + if x: + __children__[0].execute(__context__) + # This is a comment + else: + __children__[1].execute(__context__) + } + [ + Block: + [ + Code: {print(y)} [] + Literal: + AAAA + ] + Block: + [ + Literal: + BBBB + ] + ] + ] + + >>> print(parse_template('dummy.file', text='''\ + ... %for x in y: + ... AAAA + ... %if x: + ... BBBB + ... %end + ... CCCC + ... ''')) + Block: + [ + Code: + { + for x in y: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + AAAA + Code: + { + if x: + __children__[0].execute(__context__) + } + [ + Block: + [ + Literal: + BBBB + ] + ] + Literal: + CCCC + ] + ] + ] + """ + return Block(ParseContext(filename, text)) + + +def execute_template( + ast, line_directive=_default_line_directive, **local_bindings): + r"""Return the text generated by executing the given template AST. + + Keyword arguments become local variable bindings in the execution context + + >>> root_directory = os.path.abspath('/') + >>> file_name = (root_directory + 'dummy.file').replace('\\', '/') + >>> ast = parse_template(file_name, text= + ... '''Nothing + ... % if x: + ... % for i in range(3): + ... ${i} + ... % end + ... % else: + ... THIS SHOULD NOT APPEAR IN THE OUTPUT + ... ''') + >>> out = execute_template(ast, + ... line_directive='//#sourceLocation(file: "%(file)s", line: %(line)d)', + ... x=1) + >>> out = out.replace(file_name, "DUMMY-FILE") + >>> print(out, end="") + //#sourceLocation(file: "DUMMY-FILE", line: 1) + Nothing + //#sourceLocation(file: "DUMMY-FILE", line: 4) + 0 + //#sourceLocation(file: "DUMMY-FILE", line: 4) + 1 + //#sourceLocation(file: "DUMMY-FILE", line: 4) + 2 + + >>> ast = parse_template(file_name, text= + ... '''Nothing + ... % a = [] + ... % for x in range(3): + ... % a.append(x) + ... % end + ... ${a} + ... ''') + >>> out = execute_template(ast, + ... line_directive='//#sourceLocation(file: "%(file)s", line: %(line)d)', + ... x=1) + >>> out = out.replace(file_name, "DUMMY-FILE") + >>> print(out, end="") + //#sourceLocation(file: "DUMMY-FILE", line: 1) + Nothing + //#sourceLocation(file: "DUMMY-FILE", line: 6) + [0, 1, 2] + + >>> ast = parse_template(file_name, text= + ... '''Nothing + ... % a = [] + ... % for x in range(3): + ... % a.append(x) + ... % end + ... ${a} + ... ''') + >>> out = execute_template(ast, + ... line_directive='#line %(line)d "%(file)s"', x=1) + >>> out = out.replace(file_name, "DUMMY-FILE") + >>> print(out, end="") + #line 1 "DUMMY-FILE" + Nothing + #line 6 "DUMMY-FILE" + [0, 1, 2] + """ + execution_context = ExecutionContext( + line_directive=line_directive, **local_bindings) + ast.execute(execution_context) + return ''.join(execution_context.result_text) + + +def main(): + import argparse + import sys + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description='Generate Your Boilerplate!', epilog=''' + A GYB template consists of the following elements: + + - Literal text which is inserted directly into the output + + - %% or $$ in literal text, which insert literal '%' and '$' + symbols respectively. + + - Substitutions of the form ${}. The Python + expression is converted to a string and the result is inserted + into the output. + + - Python code delimited by %{...}%. Typically used to inject + definitions (functions, classes, variable bindings) into the + evaluation context of the template. Common indentation is + stripped, so you can add as much indentation to the beginning + of this code as you like + + - Lines beginning with optional whitespace followed by a single + '%' and Python code. %-lines allow you to nest other + constructs inside them. To close a level of nesting, use the + "%end" construct. + + - Lines beginning with optional whitespace and followed by a + single '%' and the token "end", which close open constructs in + %-lines. + + Example template: + + - Hello - + %{ + x = 42 + def succ(a): + return a+1 + }% + + I can assure you that ${x} < ${succ(x)} + + % if int(y) > 7: + % for i in range(3): + y is greater than seven! + % end + % else: + y is less than or equal to seven + % end + + - The End. - + + When run with "gyb -Dy=9", the output is + + - Hello - + + I can assure you that 42 < 43 + + y is greater than seven! + y is greater than seven! + y is greater than seven! + + - The End. - +''' + ) + parser.add_argument( + '-D', action='append', dest='defines', metavar='NAME=VALUE', + default=[], + help='''Bindings to be set in the template's execution context''') + + parser.add_argument( + 'file', type=argparse.FileType(), + help='Path to GYB template file (defaults to stdin)', nargs='?', + default=sys.stdin) + parser.add_argument( + '-o', dest='target', type=argparse.FileType('w'), + help='Output file (defaults to stdout)', default=sys.stdout) + parser.add_argument( + '--test', action='store_true', + default=False, help='Run a self-test') + parser.add_argument( + '--verbose-test', action='store_true', + default=False, help='Run a verbose self-test') + parser.add_argument( + '--dump', action='store_true', + default=False, help='Dump the parsed template to stdout') + parser.add_argument( + '--line-directive', + default=_default_line_directive, + help=''' + Line directive format string, which will be + provided 2 substitutions, `%%(line)d` and `%%(file)s`. + + Example: `#sourceLocation(file: "%%(file)s", line: %%(line)d)` + + The default works automatically with the `line-directive` tool, + which see for more information. + ''') + + args = parser.parse_args(sys.argv[1:]) + + if args.test or args.verbose_test: + import doctest + selfmod = sys.modules[__name__] + if doctest.testmod(selfmod, verbose=args.verbose_test or None).failed: + sys.exit(1) + + bindings = dict(x.split('=', 1) for x in args.defines) + ast = parse_template(args.file.name, args.file.read()) + if args.dump: + print(ast) + # Allow the template to open files and import .py files relative to its own + # directory + os.chdir(os.path.dirname(os.path.abspath(args.file.name))) + sys.path = ['.'] + sys.path + + args.target.write(execute_template(ast, args.line_directive, **bindings)) + + +if __name__ == '__main__': + main() From 52a49f0a8c34c9dade472bbf966e111f12373a99 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Thu, 20 Feb 2020 10:32:42 -0500 Subject: [PATCH 03/13] Added component-wise arithmetic operations --- .swiftlint.yml | 3 + Complex.xcodeproj/project.pbxproj | 10 ++ Sources/Complex/ComplexArithmetic.swift | 60 ++++++++++ Sources/Complex/Operators.swift | 24 ++++ .../ComplexTests/ComplexArithmeticTests.swift | 103 ++++++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 Sources/Complex/Operators.swift diff --git a/.swiftlint.yml b/.swiftlint.yml index fb627d6..71248be 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -57,6 +57,9 @@ opt_in_rules: reporter: "xcode" +excluded: + - Carthage + identifier_name: excluded: - i diff --git a/Complex.xcodeproj/project.pbxproj b/Complex.xcodeproj/project.pbxproj index f37fa14..bd1d708 100644 --- a/Complex.xcodeproj/project.pbxproj +++ b/Complex.xcodeproj/project.pbxproj @@ -49,6 +49,10 @@ DDB8122123F656AC0079FEB5 /* FunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */; }; DDB8122223F656AC0079FEB5 /* FunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */; }; DDB8122323F656AC0079FEB5 /* FunctionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */; }; + DDB8125923F707EE0079FEB5 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8125823F707EE0079FEB5 /* Operators.swift */; }; + DDB8125A23F707EE0079FEB5 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8125823F707EE0079FEB5 /* Operators.swift */; }; + DDB8125B23F707EE0079FEB5 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8125823F707EE0079FEB5 /* Operators.swift */; }; + DDB8125C23F707EE0079FEB5 /* Operators.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8125823F707EE0079FEB5 /* Operators.swift */; }; DDB8126223F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; DDB8126323F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; DDB8126423F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */; }; @@ -150,6 +154,7 @@ DDB8121B23F63B890079FEB5 /* Half.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Half.framework; path = Carthage/Build/Mac/Half.framework; sourceTree = ""; }; DDB8121C23F63B900079FEB5 /* Half.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Half.framework; path = Carthage/Build/iOS/Half.framework; sourceTree = ""; }; DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionsTests.swift; sourceTree = ""; }; + DDB8125823F707EE0079FEB5 /* Operators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = ""; }; DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexArithmetic.swift; sourceTree = ""; }; DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexArithmeticTests.swift; sourceTree = ""; }; DDB8126B23FA2B950079FEB5 /* gyb.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; path = gyb.py; sourceTree = ""; }; @@ -337,6 +342,7 @@ DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */, DDB8126F23FA2C210079FEB5 /* Functions.swift.gyb */, DDB8120B23F5A8E80079FEB5 /* Functions.swift */, + DDB8125823F707EE0079FEB5 /* Operators.swift */, ); path = Complex; sourceTree = ""; @@ -682,6 +688,7 @@ buildActionMask = 2147483647; files = ( DDB8126223F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, + DDB8125923F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120723F59B760079FEB5 /* Complex.swift in Sources */, DDB8120C23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -702,6 +709,7 @@ buildActionMask = 2147483647; files = ( DDB8126323F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, + DDB8125A23F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120823F59B760079FEB5 /* Complex.swift in Sources */, DDB8120D23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -722,6 +730,7 @@ buildActionMask = 2147483647; files = ( DDB8126423F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, + DDB8125B23F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120923F59B760079FEB5 /* Complex.swift in Sources */, DDB8120E23F5A8E80079FEB5 /* Functions.swift in Sources */, ); @@ -742,6 +751,7 @@ buildActionMask = 2147483647; files = ( DDB8126523F7B1C90079FEB5 /* ComplexArithmetic.swift in Sources */, + DDB8125C23F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120A23F59B760079FEB5 /* Complex.swift in Sources */, DDB8120F23F5A8E80079FEB5 /* Functions.swift in Sources */, ); diff --git a/Sources/Complex/ComplexArithmetic.swift b/Sources/Complex/ComplexArithmetic.swift index b71399e..86de047 100644 --- a/Sources/Complex/ComplexArithmetic.swift +++ b/Sources/Complex/ComplexArithmetic.swift @@ -60,6 +60,18 @@ extension Complex { // + @inlinable @inline(__always) + public static func .+ (lhs: Complex, rhs: Complex) -> Complex { + return lhs + rhs + } + + @inlinable @inline(__always) + public static func .+= (lhs: inout Complex, rhs: Complex) { + lhs = lhs .+ rhs + } + + // + @_transparent public static func - (lhs: Complex, rhs: Scalar) -> Complex { return Complex(real: lhs.real - rhs, imaginary: lhs.imaginary) @@ -69,6 +81,18 @@ extension Complex { public static func -= (lhs: inout Complex, rhs: Scalar) { lhs = lhs - rhs } + + // + + @inlinable @inline(__always) + public static func .- (lhs: Complex, rhs: Complex) -> Complex { + return lhs - rhs + } + + @inlinable @inline(__always) + public static func .-= (lhs: inout Complex, rhs: Complex) { + lhs = lhs .- rhs + } } extension Complex where Scalar: SignedNumeric { @@ -112,6 +136,18 @@ extension Complex { public static func *= (lhs: inout Complex, rhs: Scalar) { lhs = lhs * rhs } + + // + + @_transparent + public static func .* (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real * rhs.real, imaginary: lhs.imaginary * rhs.imaginary) + } + + @_transparent + public static func .*= (lhs: inout Complex, rhs: Complex) { + lhs = lhs .* rhs + } } // MARK: - Division (BinaryInteger) @@ -143,6 +179,18 @@ extension Complex where Scalar: BinaryInteger { public static func /= (lhs: inout Complex, rhs: Scalar) { lhs = lhs / rhs } + + // + + @_transparent + public static func ./ (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real / rhs.real, imaginary: lhs.imaginary / rhs.imaginary) + } + + @_transparent + public static func ./= (lhs: inout Complex, rhs: Complex) { + lhs = lhs ./ rhs + } } // MARK: - Division (SignedInteger) @@ -188,4 +236,16 @@ extension Complex where Scalar: FloatingPoint { public static func /= (lhs: inout Complex, rhs: Scalar) { lhs = lhs / rhs } + + // + + @_transparent + public static func ./ (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real / rhs.real, imaginary: lhs.imaginary / rhs.imaginary) + } + + @_transparent + public static func ./= (lhs: inout Complex, rhs: Complex) { + lhs = lhs ./ rhs + } } diff --git a/Sources/Complex/Operators.swift b/Sources/Complex/Operators.swift new file mode 100644 index 0000000..c5c567e --- /dev/null +++ b/Sources/Complex/Operators.swift @@ -0,0 +1,24 @@ +// +// Operators.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +import Foundation + +/// Component-wise addition +infix operator .+: AdditionPrecedence +infix operator .+=: AssignmentPrecedence + +/// Component-wise subtraction +infix operator .-: AdditionPrecedence +infix operator .-=: AssignmentPrecedence + +/// Component-wise multiplication +infix operator .*: MultiplicationPrecedence +infix operator .*=: AssignmentPrecedence + +/// Component-wise division +infix operator ./: MultiplicationPrecedence +infix operator ./=: AssignmentPrecedence diff --git a/Tests/ComplexTests/ComplexArithmeticTests.swift b/Tests/ComplexTests/ComplexArithmeticTests.swift index 4a3f25d..087ce2a 100644 --- a/Tests/ComplexTests/ComplexArithmeticTests.swift +++ b/Tests/ComplexTests/ComplexArithmeticTests.swift @@ -160,6 +160,23 @@ class ComplexArithmeticTests: XCTestCase { testMultiplication(Complex(real: 3.0, imaginary: 4.0), 2.0) } + func testComponentwiseMultiplication() { + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + testComponentwiseMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + testComponentwiseMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + testComponentwiseMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + } + func testDivision() { testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) @@ -192,10 +209,28 @@ class ComplexArithmeticTests: XCTestCase { testDivision(Complex(real: 3.0, imaginary: 4.0), 2.0) } + func testComponentwiseDivision() { + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) + testComponentwiseDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + testComponentwiseDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + testComponentwiseDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + testComponentwiseDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) + } + // MARK: Private Methods private func testAdditionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(complex, complex + .zero, file: file, line: line) + XCTAssertEqual(complex, complex .+ .zero, file: file, line: line) XCTAssertEqual(complex, complex + Scalar.zero, file: file, line: line) XCTAssertEqual(complex, Scalar.zero + complex, file: file, line: line) @@ -204,6 +239,7 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(result, complex, file: file, line: line) result = complex + result .+= .zero XCTAssertEqual(result, complex, file: file, line: line) result = complex @@ -213,12 +249,17 @@ class ComplexArithmeticTests: XCTestCase { private func testSubtractionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(complex, complex - .zero, file: file, line: line) + XCTAssertEqual(complex, complex .- .zero, file: file, line: line) XCTAssertEqual(complex, complex - Scalar.zero, file: file, line: line) var result = complex result -= .zero XCTAssertEqual(result, complex, file: file, line: line) + result = complex + result .-= .zero + XCTAssertEqual(result, complex, file: file, line: line) + result = complex result -= Scalar.zero XCTAssertEqual(result, complex, file: file, line: line) @@ -226,6 +267,7 @@ class ComplexArithmeticTests: XCTestCase { private func testMultiplicationWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(.zero, complex * .zero, file: file, line: line) + XCTAssertEqual(.zero, complex .* .zero, file: file, line: line) XCTAssertEqual(.zero, complex * Scalar.zero, file: file, line: line) XCTAssertEqual(.zero, Scalar.zero * complex, file: file, line: line) @@ -233,6 +275,10 @@ class ComplexArithmeticTests: XCTestCase { result *= .zero XCTAssertEqual(result, .zero, file: file, line: line) + result = complex + result .*= .zero + XCTAssertEqual(result, .zero, file: file, line: line) + result = complex result *= Scalar.zero XCTAssertEqual(result, .zero, file: file, line: line) @@ -241,6 +287,8 @@ class ComplexArithmeticTests: XCTestCase { private func testAddition(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(lhs + rhs, result, file: file, line: line) XCTAssertEqual(rhs + lhs, result, file: file, line: line) + XCTAssertEqual(lhs .+ rhs, result, file: file, line: line) + XCTAssertEqual(rhs .+ lhs, result, file: file, line: line) var complex = lhs complex += rhs @@ -249,6 +297,14 @@ class ComplexArithmeticTests: XCTestCase { complex = rhs complex += lhs XCTAssertEqual(complex, result, file: file, line: line) + + complex = lhs + complex .+= rhs + XCTAssertEqual(complex, result, file: file, line: line) + + complex = rhs + complex .+= lhs + XCTAssertEqual(complex, result, file: file, line: line) } private func testAddition(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { @@ -266,11 +322,17 @@ class ComplexArithmeticTests: XCTestCase { var complex = lhs complex -= rhs XCTAssertEqual(complex, result, file: file, line: line) + + complex = lhs + complex .-= rhs + XCTAssertEqual(complex, result, file: file, line: line) } private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { XCTAssertEqual(lhs - rhs, result, file: file, line: line) XCTAssertEqual(rhs - lhs, -result, file: file, line: line) + XCTAssertEqual(lhs .- rhs, result, file: file, line: line) + XCTAssertEqual(rhs .- lhs, -result, file: file, line: line) var complex = lhs complex -= rhs @@ -279,6 +341,14 @@ class ComplexArithmeticTests: XCTestCase { complex = rhs complex -= lhs XCTAssertEqual(complex, -result, file: file, line: line) + + complex = lhs + complex .-= rhs + XCTAssertEqual(complex, result, file: file, line: line) + + complex = rhs + complex .-= lhs + XCTAssertEqual(complex, -result, file: file, line: line) } private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { @@ -321,6 +391,17 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(complex, result, file: file, line: line) } + private func testComponentwiseMultiplication(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) { + var result = lhs .* rhs + XCTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) + XCTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) + + result = lhs + result .*= rhs + XCTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) + XCTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) + } + private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { XCTAssertEqual(lhs / rhs, result, file: file, line: line) @@ -362,4 +443,26 @@ class ComplexArithmeticTests: XCTestCase { complex /= rhs XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) } + + private func testComponentwiseDivision(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { + var result = lhs ./ rhs + XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + + result = lhs + result ./= rhs + XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + } + + private func testComponentwiseDivision(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: FloatingPoint { + var result = lhs ./ rhs + XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + + result = lhs + result ./= rhs + XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + } } From 485927e481db831b4d2d1e89dbbdf9262eccaeb5 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Thu, 20 Feb 2020 10:41:30 -0500 Subject: [PATCH 04/13] Added arithmetic operations that ignore overflow for Complex where the scalar type conforms to FixedWidthInteger --- Sources/Complex/ComplexArithmetic.swift | 126 ++++++++++++++ Sources/Complex/Operators.swift | 12 ++ .../ComplexTests/ComplexArithmeticTests.swift | 163 ++++++++++++++++++ 3 files changed, 301 insertions(+) diff --git a/Sources/Complex/ComplexArithmetic.swift b/Sources/Complex/ComplexArithmetic.swift index 86de047..9bf6c79 100644 --- a/Sources/Complex/ComplexArithmetic.swift +++ b/Sources/Complex/ComplexArithmetic.swift @@ -103,6 +103,87 @@ extension Complex where Scalar: SignedNumeric { } } +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public static func &+ (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real &+ rhs.real, imaginary: lhs.imaginary &+ rhs.imaginary) + } + + @_transparent + public static func &+= (lhs: inout Complex, rhs: Complex) { + lhs = lhs &+ rhs + } + + @_transparent + public static func &- (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real &- rhs.real, imaginary: lhs.imaginary &- rhs.imaginary) + } + + @_transparent + public static func &-= (lhs: inout Complex, rhs: Complex) { + lhs = lhs &- rhs + } + + // + + @_transparent + public static func &+ (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real &+ rhs, imaginary: lhs.imaginary) + } + + @_transparent + public static func &+ (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs &+ rhs.real, imaginary: rhs.imaginary) + } + + @_transparent + public static func &+= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs &+ rhs + } + + // + + @inlinable @inline(__always) + public static func .&+ (lhs: Complex, rhs: Complex) -> Complex { + return lhs &+ rhs + } + + @inlinable @inline(__always) + public static func .&+= (lhs: inout Complex, rhs: Complex) { + lhs = lhs .&+ rhs + } + + // + + @_transparent + public static func &- (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real &- rhs, imaginary: lhs.imaginary) + } + + @_transparent + public static func &- (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs &- rhs.real, imaginary: .zero &- rhs.imaginary) + } + + @_transparent + public static func &-= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs &- rhs + } + + // + + @inlinable @inline(__always) + public static func .&- (lhs: Complex, rhs: Complex) -> Complex { + return lhs &- rhs + } + + @inlinable @inline(__always) + public static func .&-= (lhs: inout Complex, rhs: Complex) { + lhs = lhs .&- rhs + } +} + // MARK: - Multiplication extension Complex { @@ -150,6 +231,51 @@ extension Complex { } } +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public static func &* (lhs: Complex, rhs: Complex) -> Complex { + let real = (lhs.real &* rhs.real) &- (lhs.imaginary &* rhs.imaginary) + let imaginary = (lhs.real &* rhs.imaginary) &+ (lhs.imaginary &* rhs.real) + + return Complex(real: real, imaginary: imaginary) + } + + @_transparent + public static func &*= (lhs: inout Complex, rhs: Complex) { + lhs = lhs &* rhs + } + + // + + @_transparent + public static func &* (lhs: Complex, rhs: Scalar) -> Complex { + return Complex(real: lhs.real &* rhs, imaginary: lhs.imaginary &* rhs) + } + + @_transparent + public static func &* (lhs: Scalar, rhs: Complex) -> Complex { + return Complex(real: lhs &* rhs.real, imaginary: lhs &* rhs.imaginary) + } + + @_transparent + public static func &*= (lhs: inout Complex, rhs: Scalar) { + lhs = lhs &* rhs + } + + // + + @_transparent + public static func .&* (lhs: Complex, rhs: Complex) -> Complex { + return Complex(real: lhs.real &* rhs.real, imaginary: lhs.imaginary &* rhs.imaginary) + } + + @_transparent + public static func .&*= (lhs: inout Complex, rhs: Complex) { + lhs = lhs .&* rhs + } +} + // MARK: - Division (BinaryInteger) extension Complex where Scalar: BinaryInteger { diff --git a/Sources/Complex/Operators.swift b/Sources/Complex/Operators.swift index c5c567e..8cb684f 100644 --- a/Sources/Complex/Operators.swift +++ b/Sources/Complex/Operators.swift @@ -11,14 +11,26 @@ import Foundation infix operator .+: AdditionPrecedence infix operator .+=: AssignmentPrecedence +/// Component-wise addition, ignoring overflow +infix operator .&+: AdditionPrecedence +infix operator .&+=: AssignmentPrecedence + /// Component-wise subtraction infix operator .-: AdditionPrecedence infix operator .-=: AssignmentPrecedence +/// Component-wise subtraction, ignoring overflow +infix operator .&-: AdditionPrecedence +infix operator .&-=: AssignmentPrecedence + /// Component-wise multiplication infix operator .*: MultiplicationPrecedence infix operator .*=: AssignmentPrecedence +/// Component-wise multiplication, ignoring overflow +infix operator .&*: MultiplicationPrecedence +infix operator .&*=: AssignmentPrecedence + /// Component-wise division infix operator ./: MultiplicationPrecedence infix operator ./=: AssignmentPrecedence diff --git a/Tests/ComplexTests/ComplexArithmeticTests.swift b/Tests/ComplexTests/ComplexArithmeticTests.swift index 087ce2a..f8d2253 100644 --- a/Tests/ComplexTests/ComplexArithmeticTests.swift +++ b/Tests/ComplexTests/ComplexArithmeticTests.swift @@ -96,6 +96,19 @@ class ComplexArithmeticTests: XCTestCase { testAddition(Complex(real: 1.0, imaginary: 2.0), 3.0, Complex(real: 4.0, imaginary: 2.0)) } + func testAdditionIgnoringOverflow() { + testAdditionIgnoringOverflow(forType: Int8.self) + testAdditionIgnoringOverflow(forType: Int16.self) + testAdditionIgnoringOverflow(forType: Int32.self) + testAdditionIgnoringOverflow(forType: Int64.self) + testAdditionIgnoringOverflow(forType: Int.self) + testAdditionIgnoringOverflow(forType: UInt8.self) + testAdditionIgnoringOverflow(forType: UInt16.self) + testAdditionIgnoringOverflow(forType: UInt32.self) + testAdditionIgnoringOverflow(forType: UInt64.self) + testAdditionIgnoringOverflow(forType: UInt.self) + } + func testSubtraction() { testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) @@ -128,6 +141,19 @@ class ComplexArithmeticTests: XCTestCase { testSubtraction(Complex(real: 3.0, imaginary: 4.0), 1.0, Complex(real: 2.0, imaginary: 4.0)) } + func testSubtractionIgnoringOverflow() { + testSubtractionIgnoringOverflow(forType: Int8.self) + testSubtractionIgnoringOverflow(forType: Int16.self) + testSubtractionIgnoringOverflow(forType: Int32.self) + testSubtractionIgnoringOverflow(forType: Int64.self) + testSubtractionIgnoringOverflow(forType: Int.self) + testSubtractionIgnoringOverflow(forType: UInt8.self) + testSubtractionIgnoringOverflow(forType: UInt16.self) + testSubtractionIgnoringOverflow(forType: UInt32.self) + testSubtractionIgnoringOverflow(forType: UInt64.self) + testSubtractionIgnoringOverflow(forType: UInt.self) + } + func testMultiplication() { testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) @@ -160,6 +186,19 @@ class ComplexArithmeticTests: XCTestCase { testMultiplication(Complex(real: 3.0, imaginary: 4.0), 2.0) } + func testMultiplicationIgnoringOverflow() { + testMultiplicationIgnoringOverflow(forType: Int8.self) + testMultiplicationIgnoringOverflow(forType: Int16.self) + testMultiplicationIgnoringOverflow(forType: Int32.self) + testMultiplicationIgnoringOverflow(forType: Int64.self) + testMultiplicationIgnoringOverflow(forType: Int.self) + testMultiplicationIgnoringOverflow(forType: UInt8.self) + testMultiplicationIgnoringOverflow(forType: UInt16.self) + testMultiplicationIgnoringOverflow(forType: UInt32.self) + testMultiplicationIgnoringOverflow(forType: UInt64.self) + testMultiplicationIgnoringOverflow(forType: UInt.self) + } + func testComponentwiseMultiplication() { testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) testComponentwiseMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2)) @@ -316,8 +355,62 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(complex, result, file: file, line: line) } + private func testAdditionIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + // The test is defined to "succeed" if it doesn't crash + let lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + let rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + let rhs2 = Scalar.max + + _ = lhs &+ rhs + _ = rhs &+ lhs + _ = lhs .&+ rhs + _ = rhs .&+ lhs + _ = lhs &+ rhs2 + _ = rhs2 &+ lhs + + var complex = lhs + complex &+= rhs + + complex = rhs + complex &+= lhs + + complex = lhs + complex .&+= rhs + + complex = rhs + complex .&+= lhs + + if Scalar.isSigned { + // If the scalar is signed each min is the smallest negative number. Adding these + // two together would overflow. + let lhs = Complex(real: Scalar.min, imaginary: Scalar.min) + let rhs = Complex(real: Scalar.min, imaginary: Scalar.min) + + _ = lhs &+ rhs + _ = rhs &+ lhs + _ = lhs .&+ rhs + _ = rhs .&+ lhs + + var complex = lhs + complex &+= rhs + + complex = lhs + complex &+= rhs2 + + complex = rhs + complex &+= lhs + + complex = lhs + complex .&+= rhs + + complex = rhs + complex .&+= lhs + } + } + private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(lhs - rhs, result, file: file, line: line) + XCTAssertEqual(lhs .- rhs, result, file: file, line: line) var complex = lhs complex -= rhs @@ -368,6 +461,47 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(complex, result, file: file, line: line) } + private func testSubtractionIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + // The test is defined to "succeed" if it doesn't crash + let lhs = Complex(real: Scalar.min, imaginary: Scalar.min) + let rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + let rhs2 = Scalar.max + let rhs3 = Scalar.min + + _ = lhs &- rhs + _ = lhs .&- rhs + _ = lhs &- rhs2 + _ = rhs3 &- rhs + + var complex = lhs + complex &-= rhs + + complex = lhs + complex &-= rhs2 + + complex = lhs + complex .&-= rhs + + if Scalar.isSigned { + // If the scalar is signed each min is the smallest negative number. Subtracting + // these from the max would overflow. + let lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + let rhs = Complex(real: Scalar.min, imaginary: Scalar.min) + + _ = lhs &- rhs + _ = lhs .&- rhs + + var complex = lhs + complex &-= rhs + + complex = lhs + complex &-= rhs3 + + complex = lhs + complex .&-= rhs + } + } + private func testMultiplication(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(lhs * rhs, result, file: file, line: line) XCTAssertEqual(rhs * lhs, result, file: file, line: line) @@ -381,6 +515,35 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(complex, result, file: file, line: line) } + private func testMultiplicationIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + // The test is defined to "succeed" if it doesn't crash + let lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + let rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + let rhs2 = Scalar.max + + _ = lhs &* rhs + _ = rhs &* lhs + _ = lhs .&* rhs + _ = rhs .&* lhs + _ = lhs &* rhs2 + _ = rhs2 &* lhs + + var complex = lhs + complex &*= rhs + + complex = rhs + complex &*= lhs + + complex = lhs + complex &*= rhs2 + + complex = lhs + complex .&*= rhs + + complex = rhs + complex .&*= lhs + } + private func testMultiplication(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) { let result = Complex(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs) XCTAssertEqual(lhs * rhs, result, file: file, line: line) From d89e95441ec118c06dca32c94e8e47432d2b4ae6 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Thu, 20 Feb 2020 11:16:53 -0500 Subject: [PATCH 05/13] Added trivial overflowing arithmetic functions for Complex where the scalar type conforms to FixedWidthInteger --- Sources/Complex/ComplexArithmetic.swift | 59 +++++ .../ComplexTests/ComplexArithmeticTests.swift | 221 ++++++++++++++++++ 2 files changed, 280 insertions(+) diff --git a/Sources/Complex/ComplexArithmetic.swift b/Sources/Complex/ComplexArithmetic.swift index 9bf6c79..fe4766f 100644 --- a/Sources/Complex/ComplexArithmetic.swift +++ b/Sources/Complex/ComplexArithmetic.swift @@ -184,6 +184,27 @@ extension Complex where Scalar: FixedWidthInteger { } } +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func addingReportingOverflow(_ rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.addingReportingOverflow(rhs.real) + let imaginary = self.imaginary.addingReportingOverflow(rhs.imaginary) + let overflow = real.overflow || imaginary.overflow + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: overflow) + } + + @_transparent + public func subtractingReportingOverflow(_ rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.subtractingReportingOverflow(rhs.real) + let imaginary = self.imaginary.subtractingReportingOverflow(rhs.imaginary) + let overflow = real.overflow || imaginary.overflow + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: overflow) + } +} + // MARK: - Multiplication extension Complex { @@ -276,6 +297,25 @@ extension Complex where Scalar: FixedWidthInteger { } } +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func componentwiseMultipliedFullWidth(by rhs: Complex) -> (high: Complex, low: Complex) { + let real = self.real.multipliedFullWidth(by: rhs.real) + let imaginary = self.imaginary.multipliedFullWidth(by: rhs.imaginary) + + return (high: Complex(real: real.high, imaginary: imaginary.high), low: Complex(real: real.low, imaginary: imaginary.low)) + } + + @_transparent + public func componentwiseMultipliedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.multipliedReportingOverflow(by: rhs.real) + let imaginary = self.imaginary.multipliedReportingOverflow(by: rhs.imaginary) + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: real.overflow || imaginary.overflow) + } +} + // MARK: - Division (BinaryInteger) extension Complex where Scalar: BinaryInteger { @@ -375,3 +415,22 @@ extension Complex where Scalar: FloatingPoint { lhs = lhs ./ rhs } } + +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func componentwiseDividedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.dividedReportingOverflow(by: rhs.real) + let imaginary = self.imaginary.dividedReportingOverflow(by: rhs.imaginary) + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: real.overflow || imaginary.overflow) + } + + @_transparent + public func componentwiseDividingFullWidth(_ dividend: (high: Complex, low: Complex)) -> (quotient: Complex, remainder: Complex) { + let real = self.real.dividingFullWidth((high: dividend.high.real, low: dividend.low.real)) + let imaginary = self.imaginary.dividingFullWidth((high: dividend.high.imaginary, low: dividend.low.imaginary)) + + return (quotient: Complex(real: real.quotient, imaginary: imaginary.quotient), remainder: Complex(real: real.remainder, imaginary: imaginary.remainder)) + } +} diff --git a/Tests/ComplexTests/ComplexArithmeticTests.swift b/Tests/ComplexTests/ComplexArithmeticTests.swift index f8d2253..4f5c704 100644 --- a/Tests/ComplexTests/ComplexArithmeticTests.swift +++ b/Tests/ComplexTests/ComplexArithmeticTests.swift @@ -109,6 +109,19 @@ class ComplexArithmeticTests: XCTestCase { testAdditionIgnoringOverflow(forType: UInt.self) } + func testOverflowingAddition() { + testOverflowingAddition(forType: Int8.self) + testOverflowingAddition(forType: Int16.self) + testOverflowingAddition(forType: Int32.self) + testOverflowingAddition(forType: Int64.self) + testOverflowingAddition(forType: Int.self) + testOverflowingAddition(forType: UInt8.self) + testOverflowingAddition(forType: UInt16.self) + testOverflowingAddition(forType: UInt32.self) + testOverflowingAddition(forType: UInt64.self) + testOverflowingAddition(forType: UInt.self) + } + func testSubtraction() { testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) @@ -154,6 +167,19 @@ class ComplexArithmeticTests: XCTestCase { testSubtractionIgnoringOverflow(forType: UInt.self) } + func testOverflowingSubtraction() { + testOverflowingSubtraction(forType: Int8.self) + testOverflowingSubtraction(forType: Int16.self) + testOverflowingSubtraction(forType: Int32.self) + testOverflowingSubtraction(forType: Int64.self) + testOverflowingSubtraction(forType: Int.self) + testOverflowingSubtraction(forType: UInt8.self) + testOverflowingSubtraction(forType: UInt16.self) + testOverflowingSubtraction(forType: UInt32.self) + testOverflowingSubtraction(forType: UInt64.self) + testOverflowingSubtraction(forType: UInt.self) + } + func testMultiplication() { testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) @@ -216,6 +242,19 @@ class ComplexArithmeticTests: XCTestCase { testComponentwiseMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) } + func testComponentwiseOverflowingMultiplication() { + testComponentwiseOverflowingMultiplication(forType: Int8.self) + testComponentwiseOverflowingMultiplication(forType: Int16.self) + testComponentwiseOverflowingMultiplication(forType: Int32.self) + testComponentwiseOverflowingMultiplication(forType: Int64.self) + testComponentwiseOverflowingMultiplication(forType: Int.self) + testComponentwiseOverflowingMultiplication(forType: UInt8.self) + testComponentwiseOverflowingMultiplication(forType: UInt16.self) + testComponentwiseOverflowingMultiplication(forType: UInt32.self) + testComponentwiseOverflowingMultiplication(forType: UInt64.self) + testComponentwiseOverflowingMultiplication(forType: UInt.self) + } + func testDivision() { testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) @@ -265,6 +304,19 @@ class ComplexArithmeticTests: XCTestCase { testComponentwiseDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) } + func testComponentwiseOverflowingDivision() { + testComponentwiseOverflowingDivision(forType: Int8.self) + testComponentwiseOverflowingDivision(forType: Int16.self) + testComponentwiseOverflowingDivision(forType: Int32.self) + testComponentwiseOverflowingDivision(forType: Int64.self) + testComponentwiseOverflowingDivision(forType: Int.self) + testComponentwiseOverflowingDivision(forType: UInt8.self) + testComponentwiseOverflowingDivision(forType: UInt16.self) + testComponentwiseOverflowingDivision(forType: UInt32.self) + testComponentwiseOverflowingDivision(forType: UInt64.self) + testComponentwiseOverflowingDivision(forType: UInt.self) + } + // MARK: Private Methods private func testAdditionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { @@ -408,6 +460,58 @@ class ComplexArithmeticTests: XCTestCase { } } + private func testOverflowingAddition(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: 0) + var rhs = Complex(real: Scalar.max, imaginary: 0) + var result = lhs.addingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, 0, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + + lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + } + + private func testOverflowingAddition(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: SignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: 0) + var rhs = Complex(real: Scalar.max, imaginary: 0) + var result = lhs.addingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, -2, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, 0, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) + + lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, -2, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) + } + private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(lhs - rhs, result, file: file, line: line) XCTAssertEqual(lhs .- rhs, result, file: file, line: line) @@ -502,6 +606,32 @@ class ComplexArithmeticTests: XCTestCase { } } + private func testOverflowingSubtraction(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + var lhs = Complex(real: Scalar.min, imaginary: 0) + var rhs = Complex(real: Scalar.max, imaginary: 0) + var result = lhs.subtractingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, 1, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) + + lhs = Complex(real: 0, imaginary: Scalar.min) + rhs = Complex(real: 0, imaginary: Scalar.max) + result = lhs.subtractingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, 0, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) + + lhs = Complex(real: Scalar.min, imaginary: Scalar.min) + rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + result = lhs.subtractingReportingOverflow(rhs) + + XCTAssertTrue(result.overflow, file: file, line: line) + XCTAssertEqual(result.partialValue.real, 1, file: file, line: line) + XCTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) + } + private func testMultiplication(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { XCTAssertEqual(lhs * rhs, result, file: file, line: line) XCTAssertEqual(rhs * lhs, result, file: file, line: line) @@ -565,6 +695,70 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) } + private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 2, imaginary: 2) + + let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) + XCTAssertEqual(fullWidth.high.real, 1, file: file, line: line) + XCTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) + XCTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 1, file: file, line: line) + XCTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 1, file: file, line: line) + + var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 2, imaginary: 0) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 2) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + } + + private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: SignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 4, imaginary: 4) + + let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) + XCTAssertEqual(fullWidth.high.real, 1, file: file, line: line) + XCTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) + XCTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 3, file: file, line: line) + XCTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 3, file: file, line: line) + + var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 4, imaginary: 0) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 4) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) + } + private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { XCTAssertEqual(lhs / rhs, result, file: file, line: line) @@ -628,4 +822,31 @@ class ComplexArithmeticTests: XCTestCase { XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) } + + private func testComponentwiseOverflowingDivision(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + let lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 0, imaginary: 0) + + let fullWidth = lhs.componentwiseDividingFullWidth((high: Complex(real: 1, imaginary: 1), low: Complex.zero)) + XCTAssertEqual(fullWidth.quotient.real, Scalar.isSigned ? 2 : 1, file: file, line: line) + XCTAssertEqual(fullWidth.quotient.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) + XCTAssertEqual(fullWidth.remainder.real, Scalar.isSigned ? 2 : 1, file: file, line: line) + XCTAssertEqual(fullWidth.remainder.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) + + var overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue, lhs, file: file, line: line) + + rhs = Complex(real: 0, imaginary: Scalar.max) + overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, lhs.real, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, 1, file: file, line: line) + + rhs = Complex(real: Scalar.max, imaginary: 0) + overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) + XCTAssertTrue(overflow.overflow, file: file, line: line) + XCTAssertEqual(overflow.partialValue.real, 1, file: file, line: line) + XCTAssertEqual(overflow.partialValue.imaginary, lhs.imaginary, file: file, line: line) + } } From cc4b50c194c0715b89d6f86d8082b424b8778dd7 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Fri, 21 Feb 2020 09:19:17 -0500 Subject: [PATCH 06/13] Reduced compile time by breaking up complex statements into smaller components --- Sources/Complex/Functions.swift | 39 +++++++++++---- Sources/Complex/Functions.swift.gyb | 13 +++-- Tests/ComplexTests/FunctionsTests.swift | 54 +++++++++++++++++---- Tests/ComplexTests/FunctionsTests.swift.gyb | 18 +++++-- 4 files changed, 100 insertions(+), 24 deletions(-) diff --git a/Sources/Complex/Functions.swift b/Sources/Complex/Functions.swift index 3836f34..5688896 100644 --- a/Sources/Complex/Functions.swift +++ b/Sources/Complex/Functions.swift @@ -158,17 +158,32 @@ public func sin(_ value: Complex) -> Complex { @_transparent public func asin(_ value: Complex) -> Complex { - return -.i * log(.i * value + sqrt(1.0 - value * value)) + //swiftlint:disable identifier_name + let iz = .i * value + let root = sqrt(1.0 - (value * value)) + + return -.i * log(iz + root) + //swiftlint:enable identifier_name } @_transparent public func asin(_ value: Complex) -> Complex { - return -.i * log(.i * value + sqrt(1.0 - value * value)) + //swiftlint:disable identifier_name + let iz = .i * value + let root = sqrt(1.0 - (value * value)) + + return -.i * log(iz + root) + //swiftlint:enable identifier_name } @_transparent public func asin(_ value: Complex) -> Complex { - return -.i * log(.i * value + sqrt(1.0 - value * value)) + //swiftlint:disable identifier_name + let iz = .i * value + let root = sqrt(1.0 - (value * value)) + + return -.i * log(iz + root) + //swiftlint:enable identifier_name } // @@ -212,17 +227,20 @@ public func cos(_ value: Complex) -> Complex { @_transparent public func acos(_ value: Complex) -> Complex { - return -.i * log(value + sqrt(value * value - 1.0)) + let root = sqrt((value * value) - 1.0) + return -.i * log(value + root) } @_transparent public func acos(_ value: Complex) -> Complex { - return -.i * log(value + sqrt(value * value - 1.0)) + let root = sqrt((value * value) - 1.0) + return -.i * log(value + root) } @_transparent public func acos(_ value: Complex) -> Complex { - return -.i * log(value + sqrt(value * value - 1.0)) + let root = sqrt((value * value) - 1.0) + return -.i * log(value + root) } // @@ -265,17 +283,20 @@ public func tan(_ value: Complex) -> Complex { @_transparent public func atan(_ value: Complex) -> Complex { - return .i * 0.5 * log((.i + value) / (.i - value)) + let quotient = (.i + value) / (.i - value) + return .i * 0.5 * log(quotient) } @_transparent public func atan(_ value: Complex) -> Complex { - return .i * 0.5 * log((.i + value) / (.i - value)) + let quotient = (.i + value) / (.i - value) + return .i * 0.5 * log(quotient) } @_transparent public func atan(_ value: Complex) -> Complex { - return .i * 0.5 * log((.i + value) / (.i - value)) + let quotient = (.i + value) / (.i - value) + return .i * 0.5 * log(quotient) } // diff --git a/Sources/Complex/Functions.swift.gyb b/Sources/Complex/Functions.swift.gyb index 3d1b759..a6aa480 100644 --- a/Sources/Complex/Functions.swift.gyb +++ b/Sources/Complex/Functions.swift.gyb @@ -117,7 +117,12 @@ public func sin(_ value: Complex<${type}>) -> Complex<${type}> { % for type in ["Float", "Double", "Float80"]: @_transparent public func asin(_ value: Complex<${type}>) -> Complex<${type}> { - return -.i * log(.i * value + sqrt(1.0 - value * value)) + //swiftlint:disable identifier_name + let iz = .i * value + let root = sqrt(1.0 - (value * value)) + + return -.i * log(iz + root) + //swiftlint:enable identifier_name } % end @@ -147,7 +152,8 @@ public func cos(_ value: Complex<${type}>) -> Complex<${type}> { % for type in ["Float", "Double", "Float80"]: @_transparent public func acos(_ value: Complex<${type}>) -> Complex<${type}> { - return -.i * log(value + sqrt(value * value - 1.0)) + let root = sqrt((value * value) - 1.0) + return -.i * log(value + root) } % end @@ -176,7 +182,8 @@ public func tan(_ value: Complex<${type}>) -> Complex<${type}> { % for type in ["Float", "Double", "Float80"]: @_transparent public func atan(_ value: Complex<${type}>) -> Complex<${type}> { - return .i * 0.5 * log((.i + value) / (.i - value)) + let quotient = (.i + value) / (.i - value) + return .i * 0.5 * log(quotient) } % end diff --git a/Tests/ComplexTests/FunctionsTests.swift b/Tests/ComplexTests/FunctionsTests.swift index b882cd1..63a158c 100644 --- a/Tests/ComplexTests/FunctionsTests.swift +++ b/Tests/ComplexTests/FunctionsTests.swift @@ -156,13 +156,31 @@ class FunctionsTests: XCTestCase { func test_asin() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + //swiftlint:disable identifier_name + let iz = .i * complex + let root = sqrt(1.0 - (complex * complex)) + let result = -.i * log(iz + root) + //swiftlint:enable identifier_name + + XCTAssertEqual(asin(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + //swiftlint:disable identifier_name + let iz = .i * complex + let root = sqrt(1.0 - (complex * complex)) + let result = -.i * log(iz + root) + //swiftlint:enable identifier_name + + XCTAssertEqual(asin(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + //swiftlint:disable identifier_name + let iz = .i * complex + let root = sqrt(1.0 - (complex * complex)) + let result = -.i * log(iz + root) + //swiftlint:enable identifier_name + + XCTAssertEqual(asin(complex), result, accuracy: 0.0001) } } @@ -192,13 +210,22 @@ class FunctionsTests: XCTestCase { func test_acos() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + let root = sqrt((complex * complex) - 1.0) + let result = -.i * log(complex + root) + + XCTAssertEqual(acos(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + let root = sqrt((complex * complex) - 1.0) + let result = -.i * log(complex + root) + + XCTAssertEqual(acos(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + let root = sqrt((complex * complex) - 1.0) + let result = -.i * log(complex + root) + + XCTAssertEqual(acos(complex), result, accuracy: 0.0001) } } @@ -228,13 +255,22 @@ class FunctionsTests: XCTestCase { func test_atan() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + let quotient = (.i + complex) / (.i - complex) + let result = .i * 0.5 * log(quotient) + + XCTAssertEqual(atan(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + let quotient = (.i + complex) / (.i - complex) + let result = .i * 0.5 * log(quotient) + + XCTAssertEqual(atan(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + let quotient = (.i + complex) / (.i - complex) + let result = .i * 0.5 * log(quotient) + + XCTAssertEqual(atan(complex), result, accuracy: 0.0001) } } diff --git a/Tests/ComplexTests/FunctionsTests.swift.gyb b/Tests/ComplexTests/FunctionsTests.swift.gyb index f7eff13..37a45ad 100644 --- a/Tests/ComplexTests/FunctionsTests.swift.gyb +++ b/Tests/ComplexTests/FunctionsTests.swift.gyb @@ -135,7 +135,13 @@ class FunctionsTests: XCTestCase { func test_asin() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(asin(complex), -.i * log(.i * complex + sqrt(1.0 - complex * complex)), accuracy: 0.0001) + //swiftlint:disable identifier_name + let iz = .i * complex + let root = sqrt(1.0 - (complex * complex)) + let result = -.i * log(iz + root) + //swiftlint:enable identifier_name + + XCTAssertEqual(asin(complex), result, accuracy: 0.0001) } % end } @@ -159,7 +165,10 @@ class FunctionsTests: XCTestCase { func test_acos() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(acos(complex), -.i * log(complex + sqrt(complex * complex - 1.0)), accuracy: 0.0001) + let root = sqrt((complex * complex) - 1.0) + let result = -.i * log(complex + root) + + XCTAssertEqual(acos(complex), result, accuracy: 0.0001) } % end } @@ -183,7 +192,10 @@ class FunctionsTests: XCTestCase { func test_atan() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(atan(complex), .i * 0.5 * log((.i + complex) / (.i - complex)), accuracy: 0.0001) + let quotient = (.i + complex) / (.i - complex) + let result = .i * 0.5 * log(quotient) + + XCTAssertEqual(atan(complex), result, accuracy: 0.0001) } % end } From 7be45bc3c650796d72d345a36a0bd1ee9d9c428a Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Fri, 21 Feb 2020 15:57:14 -0500 Subject: [PATCH 07/13] Created in-house assert testing functions for better propagating source method/type of assertion failures --- Complex.xcodeproj/project.pbxproj | 8 + .../ComplexTests/ComplexArithmeticTests.swift | 288 +++++++++--------- Tests/ComplexTests/ComplexTests.swift | 254 +++++++-------- Tests/ComplexTests/FunctionsTests.swift | 211 +++++++------ Tests/ComplexTests/FunctionsTests.swift.gyb | 147 +++++---- Tests/ComplexTests/TestingBase.swift | 41 +++ 6 files changed, 494 insertions(+), 455 deletions(-) create mode 100644 Tests/ComplexTests/TestingBase.swift diff --git a/Complex.xcodeproj/project.pbxproj b/Complex.xcodeproj/project.pbxproj index bd1d708..8c424e7 100644 --- a/Complex.xcodeproj/project.pbxproj +++ b/Complex.xcodeproj/project.pbxproj @@ -32,6 +32,9 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + DD6F08CD240077C300749359 /* TestingBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08CC240077C300749359 /* TestingBase.swift */; }; + DD6F08CE240077C300749359 /* TestingBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08CC240077C300749359 /* TestingBase.swift */; }; + DD6F08CF240077C300749359 /* TestingBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08CC240077C300749359 /* TestingBase.swift */; }; DDB8120723F59B760079FEB5 /* Complex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8120623F59B760079FEB5 /* Complex.swift */; }; DDB8120823F59B760079FEB5 /* Complex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8120623F59B760079FEB5 /* Complex.swift */; }; DDB8120923F59B760079FEB5 /* Complex.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB8120623F59B760079FEB5 /* Complex.swift */; }; @@ -146,6 +149,7 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + DD6F08CC240077C300749359 /* TestingBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingBase.swift; sourceTree = ""; }; DDB8120623F59B760079FEB5 /* Complex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Complex.swift; sourceTree = ""; }; DDB8120B23F5A8E80079FEB5 /* Functions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Functions.swift; sourceTree = ""; }; DDB8121023F5AEB10079FEB5 /* ComplexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexTests.swift; sourceTree = ""; }; @@ -302,6 +306,7 @@ DDFEEC4023EF13910096015C /* ComplexTests */ = { isa = PBXGroup; children = ( + DD6F08CC240077C300749359 /* TestingBase.swift */, DDB8121023F5AEB10079FEB5 /* ComplexTests.swift */, DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */, DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */, @@ -699,6 +704,7 @@ buildActionMask = 2147483647; files = ( DDB8126723F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, + DD6F08CD240077C300749359 /* TestingBase.swift in Sources */, DDB8121123F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122123F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -720,6 +726,7 @@ buildActionMask = 2147483647; files = ( DDB8126823F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, + DD6F08CE240077C300749359 /* TestingBase.swift in Sources */, DDB8121223F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122223F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -741,6 +748,7 @@ buildActionMask = 2147483647; files = ( DDB8126923F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, + DD6F08CF240077C300749359 /* TestingBase.swift in Sources */, DDB8121323F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122323F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); diff --git a/Tests/ComplexTests/ComplexArithmeticTests.swift b/Tests/ComplexTests/ComplexArithmeticTests.swift index 4f5c704..f6d795e 100644 --- a/Tests/ComplexTests/ComplexArithmeticTests.swift +++ b/Tests/ComplexTests/ComplexArithmeticTests.swift @@ -320,91 +320,91 @@ class ComplexArithmeticTests: XCTestCase { // MARK: Private Methods private func testAdditionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(complex, complex + .zero, file: file, line: line) - XCTAssertEqual(complex, complex .+ .zero, file: file, line: line) - XCTAssertEqual(complex, complex + Scalar.zero, file: file, line: line) - XCTAssertEqual(complex, Scalar.zero + complex, file: file, line: line) + CTAssertEqual(complex, complex + .zero, file: file, line: line) + CTAssertEqual(complex, complex .+ .zero, file: file, line: line) + CTAssertEqual(complex, complex + Scalar.zero, file: file, line: line) + CTAssertEqual(complex, Scalar.zero + complex, file: file, line: line) var result = complex result += .zero - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex, file: file, line: line) result = complex result .+= .zero - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex, file: file, line: line) result = complex result += Scalar.zero - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex, file: file, line: line) } private func testSubtractionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(complex, complex - .zero, file: file, line: line) - XCTAssertEqual(complex, complex .- .zero, file: file, line: line) - XCTAssertEqual(complex, complex - Scalar.zero, file: file, line: line) + CTAssertEqual(complex, complex - .zero, file: file, line: line) + CTAssertEqual(complex, complex .- .zero, file: file, line: line) + CTAssertEqual(complex, complex - Scalar.zero, file: file, line: line) var result = complex result -= .zero - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex, file: file, line: line) result = complex result .-= .zero - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex, file: file, line: line) result = complex result -= Scalar.zero - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex, file: file, line: line) } private func testMultiplicationWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(.zero, complex * .zero, file: file, line: line) - XCTAssertEqual(.zero, complex .* .zero, file: file, line: line) - XCTAssertEqual(.zero, complex * Scalar.zero, file: file, line: line) - XCTAssertEqual(.zero, Scalar.zero * complex, file: file, line: line) + CTAssertEqual(.zero, complex * .zero, file: file, line: line) + CTAssertEqual(.zero, complex .* .zero, file: file, line: line) + CTAssertEqual(.zero, complex * Scalar.zero, file: file, line: line) + CTAssertEqual(.zero, Scalar.zero * complex, file: file, line: line) var result = complex result *= .zero - XCTAssertEqual(result, .zero, file: file, line: line) + CTAssertEqual(result, .zero, file: file, line: line) result = complex result .*= .zero - XCTAssertEqual(result, .zero, file: file, line: line) + CTAssertEqual(result, .zero, file: file, line: line) result = complex result *= Scalar.zero - XCTAssertEqual(result, .zero, file: file, line: line) + CTAssertEqual(result, .zero, file: file, line: line) } private func testAddition(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(lhs + rhs, result, file: file, line: line) - XCTAssertEqual(rhs + lhs, result, file: file, line: line) - XCTAssertEqual(lhs .+ rhs, result, file: file, line: line) - XCTAssertEqual(rhs .+ lhs, result, file: file, line: line) + CTAssertEqual(lhs + rhs, result, file: file, line: line) + CTAssertEqual(rhs + lhs, result, file: file, line: line) + CTAssertEqual(lhs .+ rhs, result, file: file, line: line) + CTAssertEqual(rhs .+ lhs, result, file: file, line: line) var complex = lhs complex += rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = rhs complex += lhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = lhs complex .+= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = rhs complex .+= lhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testAddition(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(lhs + rhs, result, file: file, line: line) - XCTAssertEqual(rhs + lhs, result, file: file, line: line) + CTAssertEqual(lhs + rhs, result, file: file, line: line) + CTAssertEqual(rhs + lhs, result, file: file, line: line) var complex = lhs complex += rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testAdditionIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -465,25 +465,25 @@ class ComplexArithmeticTests: XCTestCase { var rhs = Complex(real: Scalar.max, imaginary: 0) var result = lhs.addingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) lhs = Complex(real: 0, imaginary: Scalar.max) rhs = Complex(real: 0, imaginary: Scalar.max) result = lhs.addingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, 0, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, 0, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) lhs = Complex(real: Scalar.max, imaginary: Scalar.max) rhs = Complex(real: Scalar.max, imaginary: Scalar.max) result = lhs.addingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) } private func testOverflowingAddition(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: SignedInteger { @@ -491,78 +491,78 @@ class ComplexArithmeticTests: XCTestCase { var rhs = Complex(real: Scalar.max, imaginary: 0) var result = lhs.addingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, -2, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, -2, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) lhs = Complex(real: 0, imaginary: Scalar.max) rhs = Complex(real: 0, imaginary: Scalar.max) result = lhs.addingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, 0, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, 0, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) lhs = Complex(real: Scalar.max, imaginary: Scalar.max) rhs = Complex(real: Scalar.max, imaginary: Scalar.max) result = lhs.addingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, -2, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, -2, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) } private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(lhs - rhs, result, file: file, line: line) - XCTAssertEqual(lhs .- rhs, result, file: file, line: line) + CTAssertEqual(lhs - rhs, result, file: file, line: line) + CTAssertEqual(lhs .- rhs, result, file: file, line: line) var complex = lhs complex -= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = lhs complex .-= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { - XCTAssertEqual(lhs - rhs, result, file: file, line: line) - XCTAssertEqual(rhs - lhs, -result, file: file, line: line) - XCTAssertEqual(lhs .- rhs, result, file: file, line: line) - XCTAssertEqual(rhs .- lhs, -result, file: file, line: line) + CTAssertEqual(lhs - rhs, result, file: file, line: line) + CTAssertEqual(rhs - lhs, -result, file: file, line: line) + CTAssertEqual(lhs .- rhs, result, file: file, line: line) + CTAssertEqual(rhs .- lhs, -result, file: file, line: line) var complex = lhs complex -= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = rhs complex -= lhs - XCTAssertEqual(complex, -result, file: file, line: line) + CTAssertEqual(complex, -result, file: file, line: line) complex = lhs complex .-= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = rhs complex .-= lhs - XCTAssertEqual(complex, -result, file: file, line: line) + CTAssertEqual(complex, -result, file: file, line: line) } private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(lhs - rhs, result, file: file, line: line) + CTAssertEqual(lhs - rhs, result, file: file, line: line) var complex = lhs complex -= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { - XCTAssertEqual(lhs - rhs, result, file: file, line: line) - XCTAssertEqual(rhs - lhs, -result, file: file, line: line) + CTAssertEqual(lhs - rhs, result, file: file, line: line) + CTAssertEqual(rhs - lhs, -result, file: file, line: line) var complex = lhs complex -= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testSubtractionIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -611,38 +611,38 @@ class ComplexArithmeticTests: XCTestCase { var rhs = Complex(real: Scalar.max, imaginary: 0) var result = lhs.subtractingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, 1, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, 1, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) lhs = Complex(real: 0, imaginary: Scalar.min) rhs = Complex(real: 0, imaginary: Scalar.max) result = lhs.subtractingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, 0, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, 0, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) lhs = Complex(real: Scalar.min, imaginary: Scalar.min) rhs = Complex(real: Scalar.max, imaginary: Scalar.max) result = lhs.subtractingReportingOverflow(rhs) - XCTAssertTrue(result.overflow, file: file, line: line) - XCTAssertEqual(result.partialValue.real, 1, file: file, line: line) - XCTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) + CTAssertTrue(result.overflow, file: file, line: line) + CTAssertEqual(result.partialValue.real, 1, file: file, line: line) + CTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) } private func testMultiplication(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(lhs * rhs, result, file: file, line: line) - XCTAssertEqual(rhs * lhs, result, file: file, line: line) + CTAssertEqual(lhs * rhs, result, file: file, line: line) + CTAssertEqual(rhs * lhs, result, file: file, line: line) var complex = lhs complex *= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) complex = rhs complex *= lhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testMultiplicationIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -676,23 +676,23 @@ class ComplexArithmeticTests: XCTestCase { private func testMultiplication(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) { let result = Complex(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs) - XCTAssertEqual(lhs * rhs, result, file: file, line: line) - XCTAssertEqual(rhs * lhs, result, file: file, line: line) + CTAssertEqual(lhs * rhs, result, file: file, line: line) + CTAssertEqual(rhs * lhs, result, file: file, line: line) var complex = lhs complex *= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testComponentwiseMultiplication(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) { var result = lhs .* rhs - XCTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) - XCTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) + CTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) result = lhs result .*= rhs - XCTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) - XCTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) + CTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) } private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { @@ -700,31 +700,31 @@ class ComplexArithmeticTests: XCTestCase { var rhs = Complex(real: 2, imaginary: 2) let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) - XCTAssertEqual(fullWidth.high.real, 1, file: file, line: line) - XCTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) - XCTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 1, file: file, line: line) - XCTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 1, file: file, line: line) + CTAssertEqual(fullWidth.high.real, 1, file: file, line: line) + CTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) + CTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 1, file: file, line: line) + CTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 1, file: file, line: line) var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) lhs = Complex(real: Scalar.max, imaginary: 0) rhs = Complex(real: 2, imaginary: 0) overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) lhs = Complex(real: 0, imaginary: Scalar.max) rhs = Complex(real: 0, imaginary: 2) overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) } private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: SignedInteger { @@ -732,95 +732,95 @@ class ComplexArithmeticTests: XCTestCase { var rhs = Complex(real: 4, imaginary: 4) let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) - XCTAssertEqual(fullWidth.high.real, 1, file: file, line: line) - XCTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) - XCTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 3, file: file, line: line) - XCTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 3, file: file, line: line) + CTAssertEqual(fullWidth.high.real, 1, file: file, line: line) + CTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) + CTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 3, file: file, line: line) + CTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 3, file: file, line: line) var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) lhs = Complex(real: Scalar.max, imaginary: 0) rhs = Complex(real: 4, imaginary: 0) overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) lhs = Complex(real: 0, imaginary: Scalar.max) rhs = Complex(real: 0, imaginary: 4) overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) } private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { - XCTAssertEqual(lhs / rhs, result, file: file, line: line) + CTAssertEqual(lhs / rhs, result, file: file, line: line) var complex = lhs complex /= rhs - XCTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result, file: file, line: line) } private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { - XCTAssertTrue((lhs / rhs - result).modulus < 0.0001, file: file, line: line) + CTAssertTrue((lhs / rhs - result).modulus < 0.0001, file: file, line: line) var complex = lhs complex /= rhs - XCTAssertTrue((complex - result).modulus < 0.0001, file: file, line: line) + CTAssertTrue((complex - result).modulus < 0.0001, file: file, line: line) } private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { - XCTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) var complex = lhs complex /= rhs - XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) } private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: SignedInteger { - XCTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) - XCTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) + CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) var complex = lhs complex /= rhs - XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) } private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { - XCTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) - XCTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) + CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) var complex = lhs complex /= rhs - XCTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) } private func testComponentwiseDivision(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { var result = lhs ./ rhs - XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) result = lhs result ./= rhs - XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) } private func testComponentwiseDivision(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: FloatingPoint { var result = lhs ./ rhs - XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) result = lhs result ./= rhs - XCTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - XCTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) } private func testComponentwiseOverflowingDivision(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -828,25 +828,25 @@ class ComplexArithmeticTests: XCTestCase { var rhs = Complex(real: 0, imaginary: 0) let fullWidth = lhs.componentwiseDividingFullWidth((high: Complex(real: 1, imaginary: 1), low: Complex.zero)) - XCTAssertEqual(fullWidth.quotient.real, Scalar.isSigned ? 2 : 1, file: file, line: line) - XCTAssertEqual(fullWidth.quotient.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) - XCTAssertEqual(fullWidth.remainder.real, Scalar.isSigned ? 2 : 1, file: file, line: line) - XCTAssertEqual(fullWidth.remainder.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) + CTAssertEqual(fullWidth.quotient.real, Scalar.isSigned ? 2 : 1, file: file, line: line) + CTAssertEqual(fullWidth.quotient.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) + CTAssertEqual(fullWidth.remainder.real, Scalar.isSigned ? 2 : 1, file: file, line: line) + CTAssertEqual(fullWidth.remainder.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) var overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue, lhs, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue, lhs, file: file, line: line) rhs = Complex(real: 0, imaginary: Scalar.max) overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, lhs.real, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, 1, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, lhs.real, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, 1, file: file, line: line) rhs = Complex(real: Scalar.max, imaginary: 0) overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) - XCTAssertTrue(overflow.overflow, file: file, line: line) - XCTAssertEqual(overflow.partialValue.real, 1, file: file, line: line) - XCTAssertEqual(overflow.partialValue.imaginary, lhs.imaginary, file: file, line: line) + CTAssertTrue(overflow.overflow, file: file, line: line) + CTAssertEqual(overflow.partialValue.real, 1, file: file, line: line) + CTAssertEqual(overflow.partialValue.imaginary, lhs.imaginary, file: file, line: line) } } diff --git a/Tests/ComplexTests/ComplexTests.swift b/Tests/ComplexTests/ComplexTests.swift index 5580a75..05bde7c 100644 --- a/Tests/ComplexTests/ComplexTests.swift +++ b/Tests/ComplexTests/ComplexTests.swift @@ -151,10 +151,10 @@ class ComplexTests: XCTestCase { } func testAdditiveArithmeticProtocolRequirements() { - XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) - XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) - XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) - XCTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) + CTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) + CTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) + CTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) + CTAssertEqual(Complex.zero, Complex(real: 0.0, imaginary: 0.0)) do { let lhs = Complex(real: 1.0, imaginary: 2.0) @@ -162,16 +162,16 @@ class ComplexTests: XCTestCase { var value = lhs value += rhs - XCTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, lhs + rhs) + CTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, lhs + rhs) value = lhs value -= rhs - XCTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, lhs - rhs) + CTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, lhs - rhs) } do { let lhs = Complex(real: 1.0, imaginary: 2.0) @@ -179,16 +179,16 @@ class ComplexTests: XCTestCase { var value = lhs value += rhs - XCTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, lhs + rhs) + CTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, lhs + rhs) value = lhs value -= rhs - XCTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, lhs - rhs) + CTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, lhs - rhs) } do { let lhs = Complex(real: 1.0, imaginary: 2.0) @@ -196,16 +196,16 @@ class ComplexTests: XCTestCase { var value = lhs value += rhs - XCTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, lhs + rhs) + CTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, lhs + rhs) value = lhs value -= rhs - XCTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, lhs - rhs) + CTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, lhs - rhs) } do { let lhs = Complex(real: 1.0, imaginary: 2.0) @@ -213,16 +213,16 @@ class ComplexTests: XCTestCase { var value = lhs value += rhs - XCTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) - XCTAssertEqual(value, lhs + rhs) + CTAssertEqual(lhs + rhs, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, Complex(real: 4.0, imaginary: 6.0)) + CTAssertEqual(value, lhs + rhs) value = lhs value -= rhs - XCTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) - XCTAssertEqual(value, lhs - rhs) + CTAssertEqual(lhs - rhs, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, Complex(real: -2.0, imaginary: -2.0)) + CTAssertEqual(value, lhs - rhs) } } @@ -230,86 +230,86 @@ class ComplexTests: XCTestCase { private func testInitialization(real: Scalar, imaginary: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { let complex0 = Complex() - XCTAssertEqual(complex0.real, 0, file: file, line: line) - XCTAssertEqual(complex0.imaginary, 0, file: file, line: line) + CTAssertEqual(complex0.real, 0) + CTAssertEqual(complex0.imaginary, 0) let complex1 = Complex(real: real, imaginary: imaginary) - XCTAssertEqual(complex1.real, real, file: file, line: line) - XCTAssertEqual(complex1.imaginary, imaginary, file: file, line: line) + CTAssertEqual(complex1.real, real) + CTAssertEqual(complex1.imaginary, imaginary) let complex2 = Complex(complex1) - XCTAssertEqual(complex2.real, real, file: file, line: line) - XCTAssertEqual(complex2.imaginary, imaginary, file: file, line: line) + CTAssertEqual(complex2.real, real) + CTAssertEqual(complex2.imaginary, imaginary) let complex3 = Complex(real: real, imaginary: imaginary) - XCTAssertEqual(complex3.real, Int64(real), file: file, line: line) - XCTAssertEqual(complex3.imaginary, Int64(imaginary), file: file, line: line) + CTAssertEqual(complex3.real, Int64(real)) + CTAssertEqual(complex3.imaginary, Int64(imaginary)) let complex4 = Complex(complex1) - XCTAssertEqual(complex4.real, Int64(real), file: file, line: line) - XCTAssertEqual(complex4.imaginary, Int64(imaginary), file: file, line: line) + CTAssertEqual(complex4.real, Int64(real)) + CTAssertEqual(complex4.imaginary, Int64(imaginary)) let complex5 = Complex(real: real, imaginary: imaginary) - XCTAssertEqual(complex5.real, Float80(real), file: file, line: line) - XCTAssertEqual(complex5.imaginary, Float80(imaginary), file: file, line: line) + CTAssertEqual(complex5.real, Float80(real)) + CTAssertEqual(complex5.imaginary, Float80(imaginary)) let complex6 = Complex(complex1) - XCTAssertEqual(complex6.real, Float80(real), file: file, line: line) - XCTAssertEqual(complex6.imaginary, Float80(imaginary), file: file, line: line) + CTAssertEqual(complex6.real, Float80(real)) + CTAssertEqual(complex6.imaginary, Float80(imaginary)) let complex7: Complex = [] - XCTAssertEqual(complex7.real, 0, file: file, line: line) - XCTAssertEqual(complex7.imaginary, 0, file: file, line: line) + CTAssertEqual(complex7.real, 0) + CTAssertEqual(complex7.imaginary, 0) let complex8: Complex = [real] - XCTAssertEqual(complex8.real, real, file: file, line: line) - XCTAssertEqual(complex8.imaginary, 0, file: file, line: line) + CTAssertEqual(complex8.real, real) + CTAssertEqual(complex8.imaginary, 0) let complex9: Complex = [real, imaginary] - XCTAssertEqual(complex9.real, real, file: file, line: line) - XCTAssertEqual(complex9.imaginary, imaginary, file: file, line: line) + CTAssertEqual(complex9.real, real) + CTAssertEqual(complex9.imaginary, imaginary) } private func testInitialization(real: Scalar, imaginary: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { let complex0 = Complex() - XCTAssertEqual(complex0.real, 0.0, file: file, line: line) - XCTAssertEqual(complex0.imaginary, 0.0, file: file, line: line) + CTAssertEqual(complex0.real, 0.0) + CTAssertEqual(complex0.imaginary, 0.0) let complex1 = Complex(real: real, imaginary: imaginary) - XCTAssertEqual(complex1.real, real, file: file, line: line) - XCTAssertEqual(complex1.imaginary, imaginary, file: file, line: line) + CTAssertEqual(complex1.real, real) + CTAssertEqual(complex1.imaginary, imaginary) let complex2 = Complex(complex1) - XCTAssertEqual(complex2.real, real, file: file, line: line) - XCTAssertEqual(complex2.imaginary, imaginary, file: file, line: line) + CTAssertEqual(complex2.real, real) + CTAssertEqual(complex2.imaginary, imaginary) let complex3 = Complex(real: real, imaginary: imaginary) - XCTAssertEqual(complex3.real, Int64(real), file: file, line: line) - XCTAssertEqual(complex3.imaginary, Int64(imaginary), file: file, line: line) + CTAssertEqual(complex3.real, Int64(real)) + CTAssertEqual(complex3.imaginary, Int64(imaginary)) let complex4 = Complex(complex1) - XCTAssertEqual(complex4.real, Int64(real), file: file, line: line) - XCTAssertEqual(complex4.imaginary, Int64(imaginary), file: file, line: line) + CTAssertEqual(complex4.real, Int64(real)) + CTAssertEqual(complex4.imaginary, Int64(imaginary)) let complex5 = Complex(real: real, imaginary: imaginary) - XCTAssertEqual(complex5.real, Float80(real), file: file, line: line) - XCTAssertEqual(complex5.imaginary, Float80(imaginary), file: file, line: line) + CTAssertEqual(complex5.real, Float80(real)) + CTAssertEqual(complex5.imaginary, Float80(imaginary)) let complex6 = Complex(complex1) - XCTAssertEqual(complex6.real, Float80(real), file: file, line: line) - XCTAssertEqual(complex6.imaginary, Float80(imaginary), file: file, line: line) + CTAssertEqual(complex6.real, Float80(real)) + CTAssertEqual(complex6.imaginary, Float80(imaginary)) let complex7: Complex = [] - XCTAssertEqual(complex7.real, 0.0, file: file, line: line) - XCTAssertEqual(complex7.imaginary, 0.0, file: file, line: line) + CTAssertEqual(complex7.real, 0.0) + CTAssertEqual(complex7.imaginary, 0.0) let complex8: Complex = [real] - XCTAssertEqual(complex8.real, real, file: file, line: line) - XCTAssertEqual(complex8.imaginary, 0.0, file: file, line: line) + CTAssertEqual(complex8.real, real) + CTAssertEqual(complex8.imaginary, 0.0) let complex9: Complex = [real, imaginary] - XCTAssertEqual(complex9.real, real, file: file, line: line) - XCTAssertEqual(complex9.imaginary, imaginary, file: file, line: line) + CTAssertEqual(complex9.real, real) + CTAssertEqual(complex9.imaginary, imaginary) } private func testRandomFactoryMethods(lowerBound: Scalar, upperBound: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -318,20 +318,20 @@ class ComplexTests: XCTestCase { let range: Range = lowerBound ..< upperBound let complex1 = Complex.random(in: range) - XCTAssertTrue(range.contains(complex1.real), file: file, line: line) - XCTAssertTrue(range.contains(complex1.imaginary), file: file, line: line) + CTAssertTrue(range.contains(complex1.real)) + CTAssertTrue(range.contains(complex1.imaginary)) let complex2 = Complex.random(in: range, using: &generator) - XCTAssertTrue(range.contains(complex2.real), file: file, line: line) - XCTAssertTrue(range.contains(complex2.imaginary), file: file, line: line) + CTAssertTrue(range.contains(complex2.real)) + CTAssertTrue(range.contains(complex2.imaginary)) let complex3 = Complex.random(in: closedRange) - XCTAssertTrue(closedRange.contains(complex3.real), file: file, line: line) - XCTAssertTrue(closedRange.contains(complex3.imaginary), file: file, line: line) + CTAssertTrue(closedRange.contains(complex3.real)) + CTAssertTrue(closedRange.contains(complex3.imaginary)) let complex4 = Complex.random(in: closedRange, using: &generator) - XCTAssertTrue(closedRange.contains(complex4.real), file: file, line: line) - XCTAssertTrue(closedRange.contains(complex4.imaginary), file: file, line: line) + CTAssertTrue(closedRange.contains(complex4.real)) + CTAssertTrue(closedRange.contains(complex4.imaginary)) } private func testRandomFactoryMethods(lowerBound: Scalar, upperBound: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint, Scalar.RawSignificand: FixedWidthInteger { @@ -340,20 +340,20 @@ class ComplexTests: XCTestCase { let range: Range = lowerBound ..< upperBound let complex1 = Complex.random(in: range) - XCTAssertTrue(range.contains(complex1.real), file: file, line: line) - XCTAssertTrue(range.contains(complex1.imaginary), file: file, line: line) + CTAssertTrue(range.contains(complex1.real)) + CTAssertTrue(range.contains(complex1.imaginary)) let complex2 = Complex.random(in: range, using: &generator) - XCTAssertTrue(range.contains(complex2.real), file: file, line: line) - XCTAssertTrue(range.contains(complex2.imaginary), file: file, line: line) + CTAssertTrue(range.contains(complex2.real)) + CTAssertTrue(range.contains(complex2.imaginary)) let complex3 = Complex.random(in: closedRange) - XCTAssertTrue(closedRange.contains(complex3.real), file: file, line: line) - XCTAssertTrue(closedRange.contains(complex3.imaginary), file: file, line: line) + CTAssertTrue(closedRange.contains(complex3.real)) + CTAssertTrue(closedRange.contains(complex3.imaginary)) let complex4 = Complex.random(in: closedRange, using: &generator) - XCTAssertTrue(closedRange.contains(complex4.real), file: file, line: line) - XCTAssertTrue(closedRange.contains(complex4.imaginary), file: file, line: line) + CTAssertTrue(closedRange.contains(complex4.real)) + CTAssertTrue(closedRange.contains(complex4.imaginary)) } private func testDescriptionMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) throws where Scalar: BinaryInteger { @@ -363,21 +363,21 @@ class ComplexTests: XCTestCase { let realRegex = try NSRegularExpression(pattern: "real:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.real)"))", options: []) let imaginaryRegex = try NSRegularExpression(pattern: "imaginary:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.imaginary)"))", options: []) - XCTAssertEqual(description, debugDescription, file: file, line: line) - XCTAssertTrue(realRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) - XCTAssertTrue(imaginaryRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) + CTAssertEqual(description, debugDescription) + CTAssertTrue(realRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0) + CTAssertTrue(imaginaryRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0) - XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.real)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.imaginary)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .square).contains("\(complex.real)")) + CTAssertTrue(complex.string(withNotation: .square).contains("\(complex.imaginary)")) - XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.modulus)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.angle)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.modulus)")) + CTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.angle)")) - XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.modulus)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.angle)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.modulus)")) + CTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.angle)")) - XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.modulus)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.angle)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.modulus)")) + CTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.angle)")) } private func testDescriptionMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) throws where Scalar: BinaryFloatingPoint { @@ -387,21 +387,21 @@ class ComplexTests: XCTestCase { let realRegex = try NSRegularExpression(pattern: "real:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.real)"))", options: []) let imaginaryRegex = try NSRegularExpression(pattern: "imaginary:[ ]*\(NSRegularExpression.escapedPattern(for: "\(complex.imaginary)"))", options: []) - XCTAssertEqual(description, debugDescription, file: file, line: line) - XCTAssertTrue(realRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) - XCTAssertTrue(imaginaryRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0, file: file, line: line) + CTAssertEqual(description, debugDescription) + CTAssertTrue(realRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0) + CTAssertTrue(imaginaryRegex.numberOfMatches(in: description, options: [], range: NSRange(location: 0, length: description.count)) > 0) - XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.real)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .square).contains("\(complex.imaginary)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .square).contains("\(complex.real)")) + CTAssertTrue(complex.string(withNotation: .square).contains("\(complex.imaginary)")) - XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.modulus)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.angle)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.modulus)")) + CTAssertTrue(complex.string(withNotation: .trigonometric).contains("\(complex.angle)")) - XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.modulus)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.angle)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.modulus)")) + CTAssertTrue(complex.string(withNotation: .euler).contains("\(complex.angle)")) - XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.modulus)"), file: file, line: line) - XCTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.angle)"), file: file, line: line) + CTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.modulus)")) + CTAssertTrue(complex.string(withNotation: .angle).contains("\(complex.angle)")) } private func testHashing(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: Hashable { @@ -414,72 +414,72 @@ class ComplexTests: XCTestCase { hasher.combine(complex.imaginary) let value2 = hasher.finalize() - XCTAssertEqual(value1, value2, file: file, line: line) + CTAssertEqual(value1, value2) } private func testRounding(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: FloatingPoint { - XCTAssertEqual(complex.rounded(), Complex(real: complex.real.rounded(), imaginary: complex.imaginary.rounded()), file: file, line: line) + CTAssertEqual(complex.rounded(), Complex(real: complex.real.rounded(), imaginary: complex.imaginary.rounded())) var rounded = complex rounded.round() - XCTAssertEqual(rounded, complex.rounded(), file: file, line: line) + CTAssertEqual(rounded, complex.rounded()) for rule in [FloatingPointRoundingRule.toNearestOrAwayFromZero, .toNearestOrEven, .up, .down, .towardZero, .awayFromZero] { - XCTAssertEqual(complex.rounded(rule), Complex(real: complex.real.rounded(rule), imaginary: complex.imaginary.rounded(rule)), file: file, line: line) + CTAssertEqual(complex.rounded(rule), Complex(real: complex.real.rounded(rule), imaginary: complex.imaginary.rounded(rule))) var rounded = complex rounded.round(rule) - XCTAssertEqual(rounded, complex.rounded(rule), file: file, line: line) + CTAssertEqual(rounded, complex.rounded(rule)) } } private func testConjugateMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { var conjugate = complex.conjugate() - XCTAssertEqual(complex.real, conjugate.real, file: file, line: line) - XCTAssertEqual(complex.imaginary, -conjugate.imaginary, file: file, line: line) + CTAssertEqual(complex.real, conjugate.real) + CTAssertEqual(complex.imaginary, -conjugate.imaginary) conjugate = ~complex - XCTAssertEqual(complex.real, conjugate.real, file: file, line: line) - XCTAssertEqual(complex.imaginary, -conjugate.imaginary, file: file, line: line) + CTAssertEqual(complex.real, conjugate.real) + CTAssertEqual(complex.imaginary, -conjugate.imaginary) conjugate = complex conjugate.formConjugate() - XCTAssertEqual(complex.real, conjugate.real, file: file, line: line) - XCTAssertEqual(complex.imaginary, -conjugate.imaginary, file: file, line: line) + CTAssertEqual(complex.real, conjugate.real) + CTAssertEqual(complex.imaginary, -conjugate.imaginary) } private func testNegationMethods(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { var negative = -complex - XCTAssertEqual(complex.real, -negative.real, file: file, line: line) - XCTAssertEqual(complex.imaginary, -negative.imaginary, file: file, line: line) + CTAssertEqual(complex.real, -negative.real) + CTAssertEqual(complex.imaginary, -negative.imaginary) negative = complex negative.negate() - XCTAssertEqual(complex.real, -negative.real, file: file, line: line) - XCTAssertEqual(complex.imaginary, -negative.imaginary, file: file, line: line) + CTAssertEqual(complex.real, -negative.real) + CTAssertEqual(complex.imaginary, -negative.imaginary) } private func testMultiplyByOne(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { let one = Complex.one let result = complex * one - XCTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) } private func testMultiplyByI(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { let i = Complex.i let result = complex * i - XCTAssertEqual(result.real, -complex.imaginary, file: file, line: line) - XCTAssertEqual(result.imaginary, complex.real, file: file, line: line) + CTAssertEqual(result.real, -complex.imaginary) + CTAssertEqual(result.imaginary, complex.real) } private func testPlusPrefixOperator(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - XCTAssertEqual(complex, +complex, file: file, line: line) + CTAssertEqual(complex, +complex) } private func testPolarComponents(_ complex: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { - XCTAssertEqual(complex.modulus, sqrt(complex.real * complex.real + complex.imaginary * complex.imaginary), file: file, line: line) - XCTAssertEqual(complex.angle, Scalar(atan2(Float80(complex.imaginary), Float80(complex.real))), file: file, line: line) + CTAssertEqual(complex.modulus, sqrt(complex.real * complex.real + complex.imaginary * complex.imaginary)) + CTAssertEqual(complex.angle, Scalar(atan2(Float80(complex.imaginary), Float80(complex.real)))) } } diff --git a/Tests/ComplexTests/FunctionsTests.swift b/Tests/ComplexTests/FunctionsTests.swift index 63a158c..42820db 100644 --- a/Tests/ComplexTests/FunctionsTests.swift +++ b/Tests/ComplexTests/FunctionsTests.swift @@ -14,143 +14,143 @@ class FunctionsTests: XCTestCase { // MARK: Test Methods func test_csqrt() { - XCTAssertEqual(csqrt(Half(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Half(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Half(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Half(9.0)), Complex(real: 3.0, imaginary: 0.0)) - XCTAssertEqual(csqrt(Float(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Float(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Float(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Float(9.0)), Complex(real: 3.0, imaginary: 0.0)) - XCTAssertEqual(csqrt(Double(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Double(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Double(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Double(9.0)), Complex(real: 3.0, imaginary: 0.0)) - XCTAssertEqual(csqrt(Float80(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Float80(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Float80(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Float80(9.0)), Complex(real: 3.0, imaginary: 0.0)) } func test_sqrt() { - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) - - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) - - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) - - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: -4.0)) - Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())).modulus < 0.0001) - XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: 4.0)) - Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())).modulus < 0.0001) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertTrue((sqrt(Complex(real: 0.0, imaginary: -4.0)) - Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())).modulus < 0.0001) + CTAssertTrue((sqrt(Complex(real: 0.0, imaginary: 4.0)) - Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())).modulus < 0.0001) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) } func test_abs() { - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) } func test_min() { - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) } func test_max() { - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) } func test_clamp() { - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) } func test_exp() { - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: 0.0)), Complex(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 0.5)), Complex(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi)), Complex(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex(real: 2.0, imaginary: .pi * 1.5)), Complex(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) } func test_log() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + CTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + CTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + CTAssertEqual(log(complex), Complex(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) } } func test_log10() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + CTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + CTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + CTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) } } func test_log2() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + CTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + CTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + CTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) } } func test_sin() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(sin(complex), Complex(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } } @@ -162,7 +162,7 @@ class FunctionsTests: XCTestCase { let result = -.i * log(iz + root) //swiftlint:enable identifier_name - XCTAssertEqual(asin(complex), result, accuracy: 0.0001) + CTAssertEqual(asin(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { //swiftlint:disable identifier_name @@ -171,7 +171,7 @@ class FunctionsTests: XCTestCase { let result = -.i * log(iz + root) //swiftlint:enable identifier_name - XCTAssertEqual(asin(complex), result, accuracy: 0.0001) + CTAssertEqual(asin(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { //swiftlint:disable identifier_name @@ -180,31 +180,31 @@ class FunctionsTests: XCTestCase { let result = -.i * log(iz + root) //swiftlint:enable identifier_name - XCTAssertEqual(asin(complex), result, accuracy: 0.0001) + CTAssertEqual(asin(complex), result, accuracy: 0.0001) } } func test_sinh() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + CTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + CTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + CTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) } } func test_cos() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(cos(complex), Complex(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } } @@ -213,43 +213,43 @@ class FunctionsTests: XCTestCase { let root = sqrt((complex * complex) - 1.0) let result = -.i * log(complex + root) - XCTAssertEqual(acos(complex), result, accuracy: 0.0001) + CTAssertEqual(acos(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { let root = sqrt((complex * complex) - 1.0) let result = -.i * log(complex + root) - XCTAssertEqual(acos(complex), result, accuracy: 0.0001) + CTAssertEqual(acos(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { let root = sqrt((complex * complex) - 1.0) let result = -.i * log(complex + root) - XCTAssertEqual(acos(complex), result, accuracy: 0.0001) + CTAssertEqual(acos(complex), result, accuracy: 0.0001) } } func test_cosh() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + CTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + CTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + CTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) } } func test_tan() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + CTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + CTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + CTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) } } @@ -258,31 +258,31 @@ class FunctionsTests: XCTestCase { let quotient = (.i + complex) / (.i - complex) let result = .i * 0.5 * log(quotient) - XCTAssertEqual(atan(complex), result, accuracy: 0.0001) + CTAssertEqual(atan(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { let quotient = (.i + complex) / (.i - complex) let result = .i * 0.5 * log(quotient) - XCTAssertEqual(atan(complex), result, accuracy: 0.0001) + CTAssertEqual(atan(complex), result, accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { let quotient = (.i + complex) / (.i - complex) let result = .i * 0.5 * log(quotient) - XCTAssertEqual(atan(complex), result, accuracy: 0.0001) + CTAssertEqual(atan(complex), result, accuracy: 0.0001) } } func test_tanh() { for complex in sampleComplexNumbers(ofType: Float.self) { - XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + CTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Double.self) { - XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + CTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) } for complex in sampleComplexNumbers(ofType: Float80.self) { - XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + CTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) } } @@ -295,8 +295,3 @@ class FunctionsTests: XCTestCase { Complex(real: 2.0, imaginary: .pi * 1.5)] } } - -func XCTAssertEqual(_ expression1: @autoclosure () throws -> Complex, _ expression2: @autoclosure () throws -> Complex, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) rethrows where T: FloatingPoint { - let difference = try abs(expression1() - expression2()) - XCTAssertTrue(difference.real <= accuracy && difference.imaginary <= accuracy, message(), file: file, line: line) -} diff --git a/Tests/ComplexTests/FunctionsTests.swift.gyb b/Tests/ComplexTests/FunctionsTests.swift.gyb index 37a45ad..d20c92d 100644 --- a/Tests/ComplexTests/FunctionsTests.swift.gyb +++ b/Tests/ComplexTests/FunctionsTests.swift.gyb @@ -14,96 +14,96 @@ class FunctionsTests: XCTestCase { // MARK: Test Methods func test_csqrt() { - XCTAssertEqual(csqrt(Half(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Half(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Half(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Half(9.0)), Complex(real: 3.0, imaginary: 0.0)) - XCTAssertEqual(csqrt(Float(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Float(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Float(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Float(9.0)), Complex(real: 3.0, imaginary: 0.0)) - XCTAssertEqual(csqrt(Double(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Double(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Double(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Double(9.0)), Complex(real: 3.0, imaginary: 0.0)) - XCTAssertEqual(csqrt(Float80(-4.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(csqrt(Float80(9.0)), Complex(real: 3.0, imaginary: 0.0)) + CTAssertEqual(csqrt(Float80(-4.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(csqrt(Float80(9.0)), Complex(real: 3.0, imaginary: 0.0)) } func test_sqrt() { - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) - - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) - - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) - - XCTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) - XCTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) - XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: -4.0)) - Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())).modulus < 0.0001) - XCTAssertTrue((sqrt(Complex(real: 0.0, imaginary: 4.0)) - Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())).modulus < 0.0001) - XCTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) - XCTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: -4.0)), Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 0.0, imaginary: 4.0)), Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) + + CTAssertEqual(sqrt(Complex(real: -4.0, imaginary: 0.0)), Complex(real: 0.0, imaginary: 2.0)) + CTAssertEqual(sqrt(Complex(real: 4.0, imaginary: 0.0)), Complex(real: 2.0, imaginary: 0.0)) + CTAssertTrue((sqrt(Complex(real: 0.0, imaginary: -4.0)) - Complex(real: 2.0.squareRoot(), imaginary: -2.0.squareRoot())).modulus < 0.0001) + CTAssertTrue((sqrt(Complex(real: 0.0, imaginary: 4.0)) - Complex(real: 2.0.squareRoot(), imaginary: 2.0.squareRoot())).modulus < 0.0001) + CTAssertEqual(sqrt(Complex(real: 3.0, imaginary: 4.0)), Complex(real: 2.0, imaginary: 1.0)) + CTAssertEqual(sqrt(Complex(real: -3.0, imaginary: 4.0)), Complex(real: 1.0, imaginary: 2.0)) } func test_abs() { - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) - XCTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) + CTAssertEqual(abs(Complex(real: -4.5, imaginary: 3.7)), Complex(real: 4.5, imaginary: 3.7)) } func test_min() { - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) - XCTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) + CTAssertEqual(min(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: -4.5, imaginary: 1.2)) } func test_max() { - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) - XCTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) + CTAssertEqual(max(Complex(real: -4.5, imaginary: 3.7), Complex(real: 7.0, imaginary: 1.2)), Complex(real: 7.0, imaginary: 3.7)) } func test_clamp() { - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) - XCTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), -4.0, 4.0), Complex(real: -4.0, imaginary: 3.7)) + CTAssertEqual(clamp(Complex(real: -4.5, imaginary: 3.7), Complex(real: 0.0, imaginary: 0.0), Complex(real: 2.0, imaginary: 4.0)), Complex(real: 0.0, imaginary: 3.7)) } func test_exp() { % for type in ["Float", "Double", "Float80"]: - XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: 0.0)), Complex<${type}>(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi * 0.5)), Complex<${type}>(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) - XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi)), Complex<${type}>(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) - XCTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi * 1.5)), Complex<${type}>(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: 0.0)), Complex<${type}>(real: exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi * 0.5)), Complex<${type}>(real: 0.0, imaginary: exp(2.0)), accuracy: 0.0001) + CTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi)), Complex<${type}>(real: -exp(2.0), imaginary: 0.0), accuracy: 0.0001) + CTAssertEqual(exp(Complex<${type}>(real: 2.0, imaginary: .pi * 1.5)), Complex<${type}>(real: 0.0, imaginary: -exp(2.0)), accuracy: 0.0001) % end } func test_log() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(log(complex), Complex<${type}>(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) + CTAssertEqual(log(complex), Complex<${type}>(real: log(complex.modulus), imaginary: complex.angle), accuracy: 0.0001) } % end } @@ -111,7 +111,7 @@ class FunctionsTests: XCTestCase { func test_log10() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) + CTAssertEqual(log10(complex), log(complex) / log(10), accuracy: 0.0001) } % end } @@ -119,7 +119,7 @@ class FunctionsTests: XCTestCase { func test_log2() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) + CTAssertEqual(log2(complex), log(complex) / log(2), accuracy: 0.0001) } % end } @@ -127,7 +127,7 @@ class FunctionsTests: XCTestCase { func test_sin() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(sin(complex), Complex<${type}>(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(sin(complex), Complex<${type}>(real: sin(complex.real) * cosh(complex.imaginary), imaginary: cos(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } % end } @@ -141,7 +141,7 @@ class FunctionsTests: XCTestCase { let result = -.i * log(iz + root) //swiftlint:enable identifier_name - XCTAssertEqual(asin(complex), result, accuracy: 0.0001) + CTAssertEqual(asin(complex), result, accuracy: 0.0001) } % end } @@ -149,7 +149,7 @@ class FunctionsTests: XCTestCase { func test_sinh() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) + CTAssertEqual(sinh(complex), -.i * sin(.i * complex), accuracy: 0.0001) } % end } @@ -157,7 +157,7 @@ class FunctionsTests: XCTestCase { func test_cos() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(cos(complex), Complex<${type}>(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) + CTAssertEqual(cos(complex), Complex<${type}>(real: cos(complex.real) * cosh(complex.imaginary), imaginary: -sin(complex.real) * sinh(complex.imaginary)), accuracy: 0.0001) } % end } @@ -168,7 +168,7 @@ class FunctionsTests: XCTestCase { let root = sqrt((complex * complex) - 1.0) let result = -.i * log(complex + root) - XCTAssertEqual(acos(complex), result, accuracy: 0.0001) + CTAssertEqual(acos(complex), result, accuracy: 0.0001) } % end } @@ -176,7 +176,7 @@ class FunctionsTests: XCTestCase { func test_cosh() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) + CTAssertEqual(cosh(complex), cos(.i * complex), accuracy: 0.0001) } % end } @@ -184,7 +184,7 @@ class FunctionsTests: XCTestCase { func test_tan() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) + CTAssertEqual(tan(complex), sin(complex) / cos(complex), accuracy: 0.0001) } % end } @@ -195,7 +195,7 @@ class FunctionsTests: XCTestCase { let quotient = (.i + complex) / (.i - complex) let result = .i * 0.5 * log(quotient) - XCTAssertEqual(atan(complex), result, accuracy: 0.0001) + CTAssertEqual(atan(complex), result, accuracy: 0.0001) } % end } @@ -203,7 +203,7 @@ class FunctionsTests: XCTestCase { func test_tanh() { % for type in ["Float", "Double", "Float80"]: for complex in sampleComplexNumbers(ofType: ${type}.self) { - XCTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) + CTAssertEqual(tanh(complex), -.i * tan(.i * complex), accuracy: 0.0001) } % end } @@ -217,8 +217,3 @@ class FunctionsTests: XCTestCase { Complex(real: 2.0, imaginary: .pi * 1.5)] } } - -func XCTAssertEqual(_ expression1: @autoclosure () throws -> Complex, _ expression2: @autoclosure () throws -> Complex, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) rethrows where T: FloatingPoint { - let difference = try abs(expression1() - expression2()) - XCTAssertTrue(difference.real <= accuracy && difference.imaginary <= accuracy, message(), file: file, line: line) -} diff --git a/Tests/ComplexTests/TestingBase.swift b/Tests/ComplexTests/TestingBase.swift new file mode 100644 index 0000000..5c6b5d4 --- /dev/null +++ b/Tests/ComplexTests/TestingBase.swift @@ -0,0 +1,41 @@ +// +// TestingBase.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +@testable import Complex +import XCTest + +// MARK: Internal Methods + +internal func CTAssertEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) where T: Equatable { + XCTAssertEqual(try expression1(), try expression2(), "\(testMethodDescription(forType: T.self, function: function))\(message().isEmpty ? "" : ": \(message())")", file: file, line: line) +} + +internal func CTAssertTrue(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) { + XCTAssertTrue(try expression(), "\(function))\(message().isEmpty ? "" : ": \(message())")", file: file, line: line) +} + +internal func CTAssertFalse(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) { + XCTAssertFalse(try expression(), "\(function))\(message().isEmpty ? "" : ": \(message())")", file: file, line: line) +} + +internal func CTAssertEqual(_ expression1: @autoclosure () throws -> Complex, _ expression2: @autoclosure () throws -> Complex, accuracy: T, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) rethrows where T: FloatingPoint { + let difference = try abs(expression1() - expression2()) + CTAssertTrue(difference.real <= accuracy && difference.imaginary <= accuracy, message(), function: function, file: file, line: line) +} + +// MARK: - Private Methods + +private func testMethodDescription(forType type: Scalar.Type, function: String = #function) -> String { + let description: String + if let index = function.firstIndex(of: "(") { + description = "\(function[..\(function[index...])" + } else { + description = function + } + + return description +} From 1bb883ff7fb447b2db9f98a834c570d3e653a1b8 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Fri, 21 Feb 2020 16:22:33 -0500 Subject: [PATCH 08/13] Added code coverage configuration file to explicitly ignore the code coverage of the unit testing targets --- Complex.xcodeproj/project.pbxproj | 2 ++ codecov.yml | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 codecov.yml diff --git a/Complex.xcodeproj/project.pbxproj b/Complex.xcodeproj/project.pbxproj index 8c424e7..96ebc89 100644 --- a/Complex.xcodeproj/project.pbxproj +++ b/Complex.xcodeproj/project.pbxproj @@ -150,6 +150,7 @@ /* Begin PBXFileReference section */ DD6F08CC240077C300749359 /* TestingBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingBase.swift; sourceTree = ""; }; + DD6F08D02400808300749359 /* codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = codecov.yml; sourceTree = ""; }; DDB8120623F59B760079FEB5 /* Complex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Complex.swift; sourceTree = ""; }; DDB8120B23F5A8E80079FEB5 /* Functions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Functions.swift; sourceTree = ""; }; DDB8121023F5AEB10079FEB5 /* ComplexTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplexTests.swift; sourceTree = ""; }; @@ -330,6 +331,7 @@ DDFEECAB23F1BA550096015C /* Complex.podspec */, DDB8121423F634770079FEB5 /* Cartfile.private */, DDFEECAC23F1BA550096015C /* Package.swift */, + DD6F08D02400808300749359 /* codecov.yml */, DDFEECAE23F1BA5E0096015C /* .swiftlint.yml */, DDFEECAD23F1BA5E0096015C /* .travis.yml */, DDFEECAF23F1BA680096015C /* README.md */, diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..b2351b3 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,23 @@ +codecov: + require_ci_to_pass: yes + +coverage: + precision: 2 + round: down + range: "70...100" + +parsers: + gcov: + branch_detection: + conditional: yes + loop: yes + method: no + macro: no + +comment: + layout: "reach,diff,flags,tree" + behavior: default + require_changes: no + +ignore: + - Tests/**/* From ce1c90f3376f904d415dc53790757dc2b50268de Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Fri, 21 Feb 2020 17:31:16 -0500 Subject: [PATCH 09/13] Setup Swift Package Github action --- .github/workflows/swift.yml | 15 +++++++++++++++ .gitignore | 2 ++ Package.swift | 8 ++++++-- 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/swift.yml diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml new file mode 100644 index 0000000..232b632 --- /dev/null +++ b/.github/workflows/swift.yml @@ -0,0 +1,15 @@ +name: Swift + +on: [push] + +jobs: + build: + + runs-on: macOS-latest + + steps: + - uses: actions/checkout@v2 + - name: Build + run: swift build -v + - name: Run Tests + run: swift test -v diff --git a/.gitignore b/.gitignore index a500584..692f4c0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ Complex.xcodeproj/xcuserdata .swiftpm Carthage gyb.pyc +.build +Package.resolved diff --git a/Package.swift b/Package.swift index cc91c6d..96e3b8c 100644 --- a/Package.swift +++ b/Package.swift @@ -15,10 +15,14 @@ let package = Package( .library(name: "Complex", type: .dynamic, targets: ["Complex"]) ], + dependencies: [ + .package(url: "https://github.com/SomeRandomiOSDev/Half", from: "1.0.1") + ], + targets: [ .target(name: "Complex"), - .testTarget(name: "ComplexTests", dependencies: ["Complex"]) + .testTarget(name: "ComplexTests", dependencies: ["Complex", "Half"]) ], - swiftLanguageVersions: [.version("4.0"), .version("4.2"), .version("5.0")] + swiftLanguageVersions: [.version("4"), .version("4.2"), .version("5")] ) From 0f530d7844ff2e0277d2e4d29608ac8801a24371 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Mon, 24 Feb 2020 01:02:18 -0500 Subject: [PATCH 10/13] Moved overflowing arithmetic functions into a separate source file --- Complex.xcodeproj/project.pbxproj | 20 +- Sources/Complex/ComplexArithmetic.swift | 59 --- .../ComplexOverflowingArithmetic.swift | 78 ++++ .../ComplexTests/ComplexArithmeticTests.swift | 379 ++++-------------- .../ComplexOverflowingArithmeticTests.swift | 237 +++++++++++ 5 files changed, 413 insertions(+), 360 deletions(-) create mode 100644 Sources/Complex/ComplexOverflowingArithmetic.swift create mode 100644 Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift diff --git a/Complex.xcodeproj/project.pbxproj b/Complex.xcodeproj/project.pbxproj index 96ebc89..6f1050a 100644 --- a/Complex.xcodeproj/project.pbxproj +++ b/Complex.xcodeproj/project.pbxproj @@ -32,6 +32,13 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + DD6F08BE24001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08BD24001B9A00749359 /* ComplexOverflowingArithmetic.swift */; }; + DD6F08BF24001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08BD24001B9A00749359 /* ComplexOverflowingArithmetic.swift */; }; + DD6F08C024001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08BD24001B9A00749359 /* ComplexOverflowingArithmetic.swift */; }; + DD6F08C124001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08BD24001B9A00749359 /* ComplexOverflowingArithmetic.swift */; }; + DD6F08C324001CD400749359 /* ComplexOverflowingArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08C224001CD400749359 /* ComplexOverflowingArithmeticTests.swift */; }; + DD6F08C424001CD400749359 /* ComplexOverflowingArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08C224001CD400749359 /* ComplexOverflowingArithmeticTests.swift */; }; + DD6F08C524001CD400749359 /* ComplexOverflowingArithmeticTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08C224001CD400749359 /* ComplexOverflowingArithmeticTests.swift */; }; DD6F08CD240077C300749359 /* TestingBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08CC240077C300749359 /* TestingBase.swift */; }; DD6F08CE240077C300749359 /* TestingBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08CC240077C300749359 /* TestingBase.swift */; }; DD6F08CF240077C300749359 /* TestingBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F08CC240077C300749359 /* TestingBase.swift */; }; @@ -149,6 +156,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + DD6F08BD24001B9A00749359 /* ComplexOverflowingArithmetic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexOverflowingArithmetic.swift; sourceTree = ""; }; + DD6F08C224001CD400749359 /* ComplexOverflowingArithmeticTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComplexOverflowingArithmeticTests.swift; sourceTree = ""; }; DD6F08CC240077C300749359 /* TestingBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestingBase.swift; sourceTree = ""; }; DD6F08D02400808300749359 /* codecov.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = codecov.yml; sourceTree = ""; }; DDB8120623F59B760079FEB5 /* Complex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Complex.swift; sourceTree = ""; }; @@ -310,6 +319,7 @@ DD6F08CC240077C300749359 /* TestingBase.swift */, DDB8121023F5AEB10079FEB5 /* ComplexTests.swift */, DDB8126623F7B7F40079FEB5 /* ComplexArithmeticTests.swift */, + DD6F08C224001CD400749359 /* ComplexOverflowingArithmeticTests.swift */, DDB8122023F656AC0079FEB5 /* FunctionsTests.swift */, DDB8128523FB1A430079FEB5 /* FunctionsTests.swift.gyb */, DDFEEC4323EF13910096015C /* ComplexTests-Info.plist */, @@ -347,8 +357,9 @@ children = ( DDB8120623F59B760079FEB5 /* Complex.swift */, DDB8126123F7B1C90079FEB5 /* ComplexArithmetic.swift */, - DDB8126F23FA2C210079FEB5 /* Functions.swift.gyb */, + DD6F08BD24001B9A00749359 /* ComplexOverflowingArithmetic.swift */, DDB8120B23F5A8E80079FEB5 /* Functions.swift */, + DDB8126F23FA2C210079FEB5 /* Functions.swift.gyb */, DDB8125823F707EE0079FEB5 /* Operators.swift */, ); path = Complex; @@ -698,6 +709,7 @@ DDB8125923F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120723F59B760079FEB5 /* Complex.swift in Sources */, DDB8120C23F5A8E80079FEB5 /* Functions.swift in Sources */, + DD6F08BE24001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -707,6 +719,7 @@ files = ( DDB8126723F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, DD6F08CD240077C300749359 /* TestingBase.swift in Sources */, + DD6F08C324001CD400749359 /* ComplexOverflowingArithmeticTests.swift in Sources */, DDB8121123F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122123F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -720,6 +733,7 @@ DDB8125A23F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120823F59B760079FEB5 /* Complex.swift in Sources */, DDB8120D23F5A8E80079FEB5 /* Functions.swift in Sources */, + DD6F08BF24001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -729,6 +743,7 @@ files = ( DDB8126823F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, DD6F08CE240077C300749359 /* TestingBase.swift in Sources */, + DD6F08C424001CD400749359 /* ComplexOverflowingArithmeticTests.swift in Sources */, DDB8121223F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122223F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -742,6 +757,7 @@ DDB8125B23F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120923F59B760079FEB5 /* Complex.swift in Sources */, DDB8120E23F5A8E80079FEB5 /* Functions.swift in Sources */, + DD6F08C024001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -751,6 +767,7 @@ files = ( DDB8126923F7B7F40079FEB5 /* ComplexArithmeticTests.swift in Sources */, DD6F08CF240077C300749359 /* TestingBase.swift in Sources */, + DD6F08C524001CD400749359 /* ComplexOverflowingArithmeticTests.swift in Sources */, DDB8121323F5AEB10079FEB5 /* ComplexTests.swift in Sources */, DDB8122323F656AC0079FEB5 /* FunctionsTests.swift in Sources */, ); @@ -764,6 +781,7 @@ DDB8125C23F707EE0079FEB5 /* Operators.swift in Sources */, DDB8120A23F59B760079FEB5 /* Complex.swift in Sources */, DDB8120F23F5A8E80079FEB5 /* Functions.swift in Sources */, + DD6F08C124001B9A00749359 /* ComplexOverflowingArithmetic.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/Complex/ComplexArithmetic.swift b/Sources/Complex/ComplexArithmetic.swift index fe4766f..9bf6c79 100644 --- a/Sources/Complex/ComplexArithmetic.swift +++ b/Sources/Complex/ComplexArithmetic.swift @@ -184,27 +184,6 @@ extension Complex where Scalar: FixedWidthInteger { } } -extension Complex where Scalar: FixedWidthInteger { - - @_transparent - public func addingReportingOverflow(_ rhs: Complex) -> (partialValue: Complex, overflow: Bool) { - let real = self.real.addingReportingOverflow(rhs.real) - let imaginary = self.imaginary.addingReportingOverflow(rhs.imaginary) - let overflow = real.overflow || imaginary.overflow - - return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: overflow) - } - - @_transparent - public func subtractingReportingOverflow(_ rhs: Complex) -> (partialValue: Complex, overflow: Bool) { - let real = self.real.subtractingReportingOverflow(rhs.real) - let imaginary = self.imaginary.subtractingReportingOverflow(rhs.imaginary) - let overflow = real.overflow || imaginary.overflow - - return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: overflow) - } -} - // MARK: - Multiplication extension Complex { @@ -297,25 +276,6 @@ extension Complex where Scalar: FixedWidthInteger { } } -extension Complex where Scalar: FixedWidthInteger { - - @_transparent - public func componentwiseMultipliedFullWidth(by rhs: Complex) -> (high: Complex, low: Complex) { - let real = self.real.multipliedFullWidth(by: rhs.real) - let imaginary = self.imaginary.multipliedFullWidth(by: rhs.imaginary) - - return (high: Complex(real: real.high, imaginary: imaginary.high), low: Complex(real: real.low, imaginary: imaginary.low)) - } - - @_transparent - public func componentwiseMultipliedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { - let real = self.real.multipliedReportingOverflow(by: rhs.real) - let imaginary = self.imaginary.multipliedReportingOverflow(by: rhs.imaginary) - - return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: real.overflow || imaginary.overflow) - } -} - // MARK: - Division (BinaryInteger) extension Complex where Scalar: BinaryInteger { @@ -415,22 +375,3 @@ extension Complex where Scalar: FloatingPoint { lhs = lhs ./ rhs } } - -extension Complex where Scalar: FixedWidthInteger { - - @_transparent - public func componentwiseDividedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { - let real = self.real.dividedReportingOverflow(by: rhs.real) - let imaginary = self.imaginary.dividedReportingOverflow(by: rhs.imaginary) - - return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: real.overflow || imaginary.overflow) - } - - @_transparent - public func componentwiseDividingFullWidth(_ dividend: (high: Complex, low: Complex)) -> (quotient: Complex, remainder: Complex) { - let real = self.real.dividingFullWidth((high: dividend.high.real, low: dividend.low.real)) - let imaginary = self.imaginary.dividingFullWidth((high: dividend.high.imaginary, low: dividend.low.imaginary)) - - return (quotient: Complex(real: real.quotient, imaginary: imaginary.quotient), remainder: Complex(real: real.remainder, imaginary: imaginary.remainder)) - } -} diff --git a/Sources/Complex/ComplexOverflowingArithmetic.swift b/Sources/Complex/ComplexOverflowingArithmetic.swift new file mode 100644 index 0000000..da69cce --- /dev/null +++ b/Sources/Complex/ComplexOverflowingArithmetic.swift @@ -0,0 +1,78 @@ +// +// ComplexOverflowingArithmetic.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +import Foundation + +// MARK: Overflowing Addition + +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func addingReportingOverflow(_ rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.addingReportingOverflow(rhs.real) + let imaginary = self.imaginary.addingReportingOverflow(rhs.imaginary) + let overflow = real.overflow || imaginary.overflow + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: overflow) + } +} + +// MARK: Overflowing Subtraction + +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func subtractingReportingOverflow(_ rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.subtractingReportingOverflow(rhs.real) + let imaginary = self.imaginary.subtractingReportingOverflow(rhs.imaginary) + let overflow = real.overflow || imaginary.overflow + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: overflow) + } +} + +// MARK: - Overflowing Multiplication + +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func componentwiseMultipliedFullWidth(by rhs: Complex) -> (high: Complex, low: Complex) { + let real = self.real.multipliedFullWidth(by: rhs.real) + let imaginary = self.imaginary.multipliedFullWidth(by: rhs.imaginary) + + return (high: Complex(real: real.high, imaginary: imaginary.high), low: Complex(real: real.low, imaginary: imaginary.low)) + } + + @_transparent + public func componentwiseMultipliedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.multipliedReportingOverflow(by: rhs.real) + let imaginary = self.imaginary.multipliedReportingOverflow(by: rhs.imaginary) + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: real.overflow || imaginary.overflow) + } +} + +// MARK: - Overflowing Division + +extension Complex where Scalar: FixedWidthInteger { + + @_transparent + public func componentwiseDividedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + let real = self.real.dividedReportingOverflow(by: rhs.real) + let imaginary = self.imaginary.dividedReportingOverflow(by: rhs.imaginary) + + return (partialValue: Complex(real: real.partialValue, imaginary: imaginary.partialValue), overflow: real.overflow || imaginary.overflow) + } + + @_transparent + public func componentwiseDividingFullWidth(_ dividend: (high: Complex, low: Complex)) -> (quotient: Complex, remainder: Complex) { + let real = self.real.dividingFullWidth((high: dividend.high.real, low: dividend.low.real)) + let imaginary = self.imaginary.dividingFullWidth((high: dividend.high.imaginary, low: dividend.low.imaginary)) + + return (quotient: Complex(real: real.quotient, imaginary: imaginary.quotient), remainder: Complex(real: real.remainder, imaginary: imaginary.remainder)) + } +} diff --git a/Tests/ComplexTests/ComplexArithmeticTests.swift b/Tests/ComplexTests/ComplexArithmeticTests.swift index f6d795e..0d1775e 100644 --- a/Tests/ComplexTests/ComplexArithmeticTests.swift +++ b/Tests/ComplexTests/ComplexArithmeticTests.swift @@ -109,19 +109,6 @@ class ComplexArithmeticTests: XCTestCase { testAdditionIgnoringOverflow(forType: UInt.self) } - func testOverflowingAddition() { - testOverflowingAddition(forType: Int8.self) - testOverflowingAddition(forType: Int16.self) - testOverflowingAddition(forType: Int32.self) - testOverflowingAddition(forType: Int64.self) - testOverflowingAddition(forType: Int.self) - testOverflowingAddition(forType: UInt8.self) - testOverflowingAddition(forType: UInt16.self) - testOverflowingAddition(forType: UInt32.self) - testOverflowingAddition(forType: UInt64.self) - testOverflowingAddition(forType: UInt.self) - } - func testSubtraction() { testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) testSubtraction(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: 2, imaginary: 2)) @@ -167,19 +154,6 @@ class ComplexArithmeticTests: XCTestCase { testSubtractionIgnoringOverflow(forType: UInt.self) } - func testOverflowingSubtraction() { - testOverflowingSubtraction(forType: Int8.self) - testOverflowingSubtraction(forType: Int16.self) - testOverflowingSubtraction(forType: Int32.self) - testOverflowingSubtraction(forType: Int64.self) - testOverflowingSubtraction(forType: Int.self) - testOverflowingSubtraction(forType: UInt8.self) - testOverflowingSubtraction(forType: UInt16.self) - testOverflowingSubtraction(forType: UInt32.self) - testOverflowingSubtraction(forType: UInt64.self) - testOverflowingSubtraction(forType: UInt.self) - } - func testMultiplication() { testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) testMultiplication(Complex(real: 3, imaginary: 4), Complex(real: 1, imaginary: 2), Complex(real: -5, imaginary: 10)) @@ -242,19 +216,6 @@ class ComplexArithmeticTests: XCTestCase { testComponentwiseMultiplication(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) } - func testComponentwiseOverflowingMultiplication() { - testComponentwiseOverflowingMultiplication(forType: Int8.self) - testComponentwiseOverflowingMultiplication(forType: Int16.self) - testComponentwiseOverflowingMultiplication(forType: Int32.self) - testComponentwiseOverflowingMultiplication(forType: Int64.self) - testComponentwiseOverflowingMultiplication(forType: Int.self) - testComponentwiseOverflowingMultiplication(forType: UInt8.self) - testComponentwiseOverflowingMultiplication(forType: UInt16.self) - testComponentwiseOverflowingMultiplication(forType: UInt32.self) - testComponentwiseOverflowingMultiplication(forType: UInt64.self) - testComponentwiseOverflowingMultiplication(forType: UInt.self) - } - func testDivision() { testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) testDivision(Complex(real: 3, imaginary: 4), Complex(real: 2, imaginary: 1), Complex(real: 2, imaginary: 1)) @@ -304,107 +265,94 @@ class ComplexArithmeticTests: XCTestCase { testComponentwiseDivision(Complex(real: 3.0, imaginary: 4.0), Complex(real: 1.0, imaginary: 2.0)) } - func testComponentwiseOverflowingDivision() { - testComponentwiseOverflowingDivision(forType: Int8.self) - testComponentwiseOverflowingDivision(forType: Int16.self) - testComponentwiseOverflowingDivision(forType: Int32.self) - testComponentwiseOverflowingDivision(forType: Int64.self) - testComponentwiseOverflowingDivision(forType: Int.self) - testComponentwiseOverflowingDivision(forType: UInt8.self) - testComponentwiseOverflowingDivision(forType: UInt16.self) - testComponentwiseOverflowingDivision(forType: UInt32.self) - testComponentwiseOverflowingDivision(forType: UInt64.self) - testComponentwiseOverflowingDivision(forType: UInt.self) - } - // MARK: Private Methods private func testAdditionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(complex, complex + .zero, file: file, line: line) - CTAssertEqual(complex, complex .+ .zero, file: file, line: line) - CTAssertEqual(complex, complex + Scalar.zero, file: file, line: line) - CTAssertEqual(complex, Scalar.zero + complex, file: file, line: line) + CTAssertEqual(complex, complex + .zero) + CTAssertEqual(complex, complex .+ .zero) + CTAssertEqual(complex, complex + Scalar.zero) + CTAssertEqual(complex, Scalar.zero + complex) var result = complex result += .zero - CTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) result = complex result .+= .zero - CTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) result = complex result += Scalar.zero - CTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) } private func testSubtractionWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(complex, complex - .zero, file: file, line: line) - CTAssertEqual(complex, complex .- .zero, file: file, line: line) - CTAssertEqual(complex, complex - Scalar.zero, file: file, line: line) + CTAssertEqual(complex, complex - .zero) + CTAssertEqual(complex, complex .- .zero) + CTAssertEqual(complex, complex - Scalar.zero) var result = complex result -= .zero - CTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) result = complex result .-= .zero - CTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) result = complex result -= Scalar.zero - CTAssertEqual(result, complex, file: file, line: line) + CTAssertEqual(result, complex) } private func testMultiplicationWithZero(_ complex: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(.zero, complex * .zero, file: file, line: line) - CTAssertEqual(.zero, complex .* .zero, file: file, line: line) - CTAssertEqual(.zero, complex * Scalar.zero, file: file, line: line) - CTAssertEqual(.zero, Scalar.zero * complex, file: file, line: line) + CTAssertEqual(.zero, complex * .zero) + CTAssertEqual(.zero, complex .* .zero) + CTAssertEqual(.zero, complex * Scalar.zero) + CTAssertEqual(.zero, Scalar.zero * complex) var result = complex result *= .zero - CTAssertEqual(result, .zero, file: file, line: line) + CTAssertEqual(result, .zero) result = complex result .*= .zero - CTAssertEqual(result, .zero, file: file, line: line) + CTAssertEqual(result, .zero) result = complex result *= Scalar.zero - CTAssertEqual(result, .zero, file: file, line: line) + CTAssertEqual(result, .zero) } private func testAddition(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(lhs + rhs, result, file: file, line: line) - CTAssertEqual(rhs + lhs, result, file: file, line: line) - CTAssertEqual(lhs .+ rhs, result, file: file, line: line) - CTAssertEqual(rhs .+ lhs, result, file: file, line: line) + CTAssertEqual(lhs + rhs, result) + CTAssertEqual(rhs + lhs, result) + CTAssertEqual(lhs .+ rhs, result) + CTAssertEqual(rhs .+ lhs, result) var complex = lhs complex += rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = rhs complex += lhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = lhs complex .+= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = rhs complex .+= lhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testAddition(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(lhs + rhs, result, file: file, line: line) - CTAssertEqual(rhs + lhs, result, file: file, line: line) + CTAssertEqual(lhs + rhs, result) + CTAssertEqual(rhs + lhs, result) var complex = lhs complex += rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testAdditionIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -460,109 +408,57 @@ class ComplexArithmeticTests: XCTestCase { } } - private func testOverflowingAddition(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { - var lhs = Complex(real: Scalar.max, imaginary: 0) - var rhs = Complex(real: Scalar.max, imaginary: 0) - var result = lhs.addingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) - - lhs = Complex(real: 0, imaginary: Scalar.max) - rhs = Complex(real: 0, imaginary: Scalar.max) - result = lhs.addingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, 0, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) - - lhs = Complex(real: Scalar.max, imaginary: Scalar.max) - rhs = Complex(real: Scalar.max, imaginary: Scalar.max) - result = lhs.addingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, Scalar.max - 1, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, Scalar.max - 1, file: file, line: line) - } - - private func testOverflowingAddition(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: SignedInteger { - var lhs = Complex(real: Scalar.max, imaginary: 0) - var rhs = Complex(real: Scalar.max, imaginary: 0) - var result = lhs.addingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, -2, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) - - lhs = Complex(real: 0, imaginary: Scalar.max) - rhs = Complex(real: 0, imaginary: Scalar.max) - result = lhs.addingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, 0, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) - - lhs = Complex(real: Scalar.max, imaginary: Scalar.max) - rhs = Complex(real: Scalar.max, imaginary: Scalar.max) - result = lhs.addingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, -2, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, -2, file: file, line: line) - } - private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(lhs - rhs, result, file: file, line: line) - CTAssertEqual(lhs .- rhs, result, file: file, line: line) + CTAssertEqual(lhs - rhs, result) + CTAssertEqual(lhs .- rhs, result) var complex = lhs complex -= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = lhs complex .-= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testSubtraction(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { - CTAssertEqual(lhs - rhs, result, file: file, line: line) - CTAssertEqual(rhs - lhs, -result, file: file, line: line) - CTAssertEqual(lhs .- rhs, result, file: file, line: line) - CTAssertEqual(rhs .- lhs, -result, file: file, line: line) + CTAssertEqual(lhs - rhs, result) + CTAssertEqual(rhs - lhs, -result) + CTAssertEqual(lhs .- rhs, result) + CTAssertEqual(rhs .- lhs, -result) var complex = lhs complex -= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = rhs complex -= lhs - CTAssertEqual(complex, -result, file: file, line: line) + CTAssertEqual(complex, -result) complex = lhs complex .-= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = rhs complex .-= lhs - CTAssertEqual(complex, -result, file: file, line: line) + CTAssertEqual(complex, -result) } private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(lhs - rhs, result, file: file, line: line) + CTAssertEqual(lhs - rhs, result) var complex = lhs complex -= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testSubtraction(_ lhs: Complex, _ rhs: Scalar, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: SignedNumeric { - CTAssertEqual(lhs - rhs, result, file: file, line: line) - CTAssertEqual(rhs - lhs, -result, file: file, line: line) + CTAssertEqual(lhs - rhs, result) + CTAssertEqual(rhs - lhs, -result) var complex = lhs complex -= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testSubtractionIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -606,43 +502,17 @@ class ComplexArithmeticTests: XCTestCase { } } - private func testOverflowingSubtraction(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { - var lhs = Complex(real: Scalar.min, imaginary: 0) - var rhs = Complex(real: Scalar.max, imaginary: 0) - var result = lhs.subtractingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, 1, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, 0, file: file, line: line) - - lhs = Complex(real: 0, imaginary: Scalar.min) - rhs = Complex(real: 0, imaginary: Scalar.max) - result = lhs.subtractingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, 0, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) - - lhs = Complex(real: Scalar.min, imaginary: Scalar.min) - rhs = Complex(real: Scalar.max, imaginary: Scalar.max) - result = lhs.subtractingReportingOverflow(rhs) - - CTAssertTrue(result.overflow, file: file, line: line) - CTAssertEqual(result.partialValue.real, 1, file: file, line: line) - CTAssertEqual(result.partialValue.imaginary, 1, file: file, line: line) - } - private func testMultiplication(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) { - CTAssertEqual(lhs * rhs, result, file: file, line: line) - CTAssertEqual(rhs * lhs, result, file: file, line: line) + CTAssertEqual(lhs * rhs, result) + CTAssertEqual(rhs * lhs, result) var complex = lhs complex *= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) complex = rhs complex *= lhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testMultiplicationIgnoringOverflow(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { @@ -676,177 +546,86 @@ class ComplexArithmeticTests: XCTestCase { private func testMultiplication(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) { let result = Complex(real: lhs.real * rhs, imaginary: lhs.imaginary * rhs) - CTAssertEqual(lhs * rhs, result, file: file, line: line) - CTAssertEqual(rhs * lhs, result, file: file, line: line) + CTAssertEqual(lhs * rhs, result) + CTAssertEqual(rhs * lhs, result) var complex = lhs complex *= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testComponentwiseMultiplication(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) { var result = lhs .* rhs - CTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) - CTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real * rhs.real) + CTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary) result = lhs result .*= rhs - CTAssertEqual(result.real, lhs.real * rhs.real, file: file, line: line) - CTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary, file: file, line: line) - } - - private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { - var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) - var rhs = Complex(real: 2, imaginary: 2) - - let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) - CTAssertEqual(fullWidth.high.real, 1, file: file, line: line) - CTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) - CTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 1, file: file, line: line) - CTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 1, file: file, line: line) - - var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) - - lhs = Complex(real: Scalar.max, imaginary: 0) - rhs = Complex(real: 2, imaginary: 0) - overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, Scalar.max - 1, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) - - lhs = Complex(real: 0, imaginary: Scalar.max) - rhs = Complex(real: 0, imaginary: 2) - overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1, file: file, line: line) - } - - private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger, Scalar: SignedInteger { - var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) - var rhs = Complex(real: 4, imaginary: 4) - - let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) - CTAssertEqual(fullWidth.high.real, 1, file: file, line: line) - CTAssertEqual(fullWidth.high.imaginary, 1, file: file, line: line) - CTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 3, file: file, line: line) - CTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 3, file: file, line: line) - - var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) - - lhs = Complex(real: Scalar.max, imaginary: 0) - rhs = Complex(real: 4, imaginary: 0) - overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, -4, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, 0, file: file, line: line) - - lhs = Complex(real: 0, imaginary: Scalar.max) - rhs = Complex(real: 0, imaginary: 4) - overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) - - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, 0, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, -4, file: file, line: line) + CTAssertEqual(result.real, lhs.real * rhs.real) + CTAssertEqual(result.imaginary, lhs.imaginary * rhs.imaginary) } private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { - CTAssertEqual(lhs / rhs, result, file: file, line: line) + CTAssertEqual(lhs / rhs, result) var complex = lhs complex /= rhs - CTAssertEqual(complex, result, file: file, line: line) + CTAssertEqual(complex, result) } private func testDivision(_ lhs: Complex, _ rhs: Complex, _ result: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { - CTAssertTrue((lhs / rhs - result).modulus < 0.0001, file: file, line: line) + CTAssertTrue((lhs / rhs - result).modulus < 0.0001) var complex = lhs complex /= rhs - CTAssertTrue((complex - result).modulus < 0.0001, file: file, line: line) + CTAssertTrue((complex - result).modulus < 0.0001) } private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { - CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)) var complex = lhs complex /= rhs - CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)) } private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: SignedInteger { - CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) - CTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) + CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)) + CTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs)) var complex = lhs complex /= rhs - CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)) } private func testDivision(_ lhs: Complex, _ rhs: Scalar, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryFloatingPoint { - CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) - CTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs), file: file, line: line) + CTAssertEqual(lhs / rhs, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)) + CTAssertEqual(rhs / lhs, (Complex(real: rhs, imaginary: 0) / lhs)) var complex = lhs complex /= rhs - CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs), file: file, line: line) + CTAssertEqual(complex, Complex(real: lhs.real / rhs, imaginary: lhs.imaginary / rhs)) } private func testComponentwiseDivision(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: BinaryInteger { var result = lhs ./ rhs - CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary) result = lhs result ./= rhs - CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary) } private func testComponentwiseDivision(_ lhs: Complex, _ rhs: Complex, file: StaticString = #file, line: UInt = #line) where Scalar: FloatingPoint { var result = lhs ./ rhs - CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary) result = lhs result ./= rhs - CTAssertEqual(result.real, lhs.real / rhs.real, file: file, line: line) - CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary, file: file, line: line) - } - - private func testComponentwiseOverflowingDivision(forType: Scalar.Type, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { - let lhs = Complex(real: Scalar.max, imaginary: Scalar.max) - var rhs = Complex(real: 0, imaginary: 0) - - let fullWidth = lhs.componentwiseDividingFullWidth((high: Complex(real: 1, imaginary: 1), low: Complex.zero)) - CTAssertEqual(fullWidth.quotient.real, Scalar.isSigned ? 2 : 1, file: file, line: line) - CTAssertEqual(fullWidth.quotient.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) - CTAssertEqual(fullWidth.remainder.real, Scalar.isSigned ? 2 : 1, file: file, line: line) - CTAssertEqual(fullWidth.remainder.imaginary, Scalar.isSigned ? 2 : 1, file: file, line: line) - - var overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue, lhs, file: file, line: line) - - rhs = Complex(real: 0, imaginary: Scalar.max) - overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, lhs.real, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, 1, file: file, line: line) - - rhs = Complex(real: Scalar.max, imaginary: 0) - overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) - CTAssertTrue(overflow.overflow, file: file, line: line) - CTAssertEqual(overflow.partialValue.real, 1, file: file, line: line) - CTAssertEqual(overflow.partialValue.imaginary, lhs.imaginary, file: file, line: line) + CTAssertEqual(result.real, lhs.real / rhs.real) + CTAssertEqual(result.imaginary, lhs.imaginary / rhs.imaginary) } } diff --git a/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift b/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift new file mode 100644 index 0000000..c3339fa --- /dev/null +++ b/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift @@ -0,0 +1,237 @@ +// +// ComplexOverflowingArithmeticTests.swift +// Complex +// +// Copyright © 2020 SomeRandomiOSDev. All rights reserved. +// + +@testable import Complex +import XCTest + +class ComplexOverflowingArithmeticTests: XCTestCase { + + // MARK: Test Methods + + func testOverflowingAddition() { + testOverflowingAddition(forType: Int8.self) + testOverflowingAddition(forType: Int16.self) + testOverflowingAddition(forType: Int32.self) + testOverflowingAddition(forType: Int64.self) + testOverflowingAddition(forType: Int.self) + testOverflowingAddition(forType: UInt8.self) + testOverflowingAddition(forType: UInt16.self) + testOverflowingAddition(forType: UInt32.self) + testOverflowingAddition(forType: UInt64.self) + testOverflowingAddition(forType: UInt.self) + } + + func testOverflowingSubtraction() { + testOverflowingSubtraction(forType: Int8.self) + testOverflowingSubtraction(forType: Int16.self) + testOverflowingSubtraction(forType: Int32.self) + testOverflowingSubtraction(forType: Int64.self) + testOverflowingSubtraction(forType: Int.self) + testOverflowingSubtraction(forType: UInt8.self) + testOverflowingSubtraction(forType: UInt16.self) + testOverflowingSubtraction(forType: UInt32.self) + testOverflowingSubtraction(forType: UInt64.self) + testOverflowingSubtraction(forType: UInt.self) + } + + func testComponentwiseOverflowingMultiplication() { + testComponentwiseOverflowingMultiplication(forType: Int8.self) + testComponentwiseOverflowingMultiplication(forType: Int16.self) + testComponentwiseOverflowingMultiplication(forType: Int32.self) + testComponentwiseOverflowingMultiplication(forType: Int64.self) + testComponentwiseOverflowingMultiplication(forType: Int.self) + testComponentwiseOverflowingMultiplication(forType: UInt8.self) + testComponentwiseOverflowingMultiplication(forType: UInt16.self) + testComponentwiseOverflowingMultiplication(forType: UInt32.self) + testComponentwiseOverflowingMultiplication(forType: UInt64.self) + testComponentwiseOverflowingMultiplication(forType: UInt.self) + } + + func testComponentwiseOverflowingDivision() { + testComponentwiseOverflowingDivision(forType: Int8.self) + testComponentwiseOverflowingDivision(forType: Int16.self) + testComponentwiseOverflowingDivision(forType: Int32.self) + testComponentwiseOverflowingDivision(forType: Int64.self) + testComponentwiseOverflowingDivision(forType: Int.self) + testComponentwiseOverflowingDivision(forType: UInt8.self) + testComponentwiseOverflowingDivision(forType: UInt16.self) + testComponentwiseOverflowingDivision(forType: UInt32.self) + testComponentwiseOverflowingDivision(forType: UInt64.self) + testComponentwiseOverflowingDivision(forType: UInt.self) + } + + // MARK: Private Methods + + private func testOverflowingAddition(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: 0) + var rhs = Complex(real: Scalar.max, imaginary: 0) + var result = lhs.addingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, Scalar.max - 1) + CTAssertEqual(result.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, 0) + CTAssertEqual(result.partialValue.imaginary, Scalar.max - 1) + + lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, Scalar.max - 1) + CTAssertEqual(result.partialValue.imaginary, Scalar.max - 1) + } + + private func testOverflowingAddition(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: SignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: 0) + var rhs = Complex(real: Scalar.max, imaginary: 0) + var result = lhs.addingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, -2) + CTAssertEqual(result.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, 0) + CTAssertEqual(result.partialValue.imaginary, -2) + + lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + result = lhs.addingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, -2) + CTAssertEqual(result.partialValue.imaginary, -2) + } + + private func testOverflowingSubtraction(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var lhs = Complex(real: Scalar.min, imaginary: 0) + var rhs = Complex(real: Scalar.max, imaginary: 0) + var result = lhs.subtractingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, 1) + CTAssertEqual(result.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.min) + rhs = Complex(real: 0, imaginary: Scalar.max) + result = lhs.subtractingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, 0) + CTAssertEqual(result.partialValue.imaginary, 1) + + lhs = Complex(real: Scalar.min, imaginary: Scalar.min) + rhs = Complex(real: Scalar.max, imaginary: Scalar.max) + result = lhs.subtractingReportingOverflow(rhs) + + CTAssertTrue(result.overflow) + CTAssertEqual(result.partialValue.real, 1) + CTAssertEqual(result.partialValue.imaginary, 1) + } + + private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 2, imaginary: 2) + + let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) + CTAssertEqual(fullWidth.high.real, 1) + CTAssertEqual(fullWidth.high.imaginary, 1) + CTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 1) + CTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 1) + + var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, Scalar.max - 1) + CTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 2, imaginary: 0) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, Scalar.max - 1) + CTAssertEqual(overflow.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 2) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 0) + CTAssertEqual(overflow.partialValue.imaginary, Scalar.max - 1) + } + + private func testComponentwiseOverflowingMultiplication(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: SignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 4, imaginary: 4) + + let fullWidth = lhs.componentwiseMultipliedFullWidth(by: rhs) + CTAssertEqual(fullWidth.high.real, 1) + CTAssertEqual(fullWidth.high.imaginary, 1) + CTAssertEqual(fullWidth.low.real, Scalar.Magnitude.max - 3) + CTAssertEqual(fullWidth.low.imaginary, Scalar.Magnitude.max - 3) + + var overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, -4) + CTAssertEqual(overflow.partialValue.imaginary, -4) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 4, imaginary: 0) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, -4) + CTAssertEqual(overflow.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 4) + overflow = lhs.componentwiseMultipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 0) + CTAssertEqual(overflow.partialValue.imaginary, -4) + } + + private func testComponentwiseOverflowingDivision(forType: Scalar.Type) where Scalar: FixedWidthInteger { + let lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 0, imaginary: 0) + + let fullWidth = lhs.componentwiseDividingFullWidth((high: Complex(real: 1, imaginary: 1), low: Complex.zero)) + CTAssertEqual(fullWidth.quotient.real, Scalar.isSigned ? 2 : 1) + CTAssertEqual(fullWidth.quotient.imaginary, Scalar.isSigned ? 2 : 1) + CTAssertEqual(fullWidth.remainder.real, Scalar.isSigned ? 2 : 1) + CTAssertEqual(fullWidth.remainder.imaginary, Scalar.isSigned ? 2 : 1) + + var overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue, lhs) + + rhs = Complex(real: 0, imaginary: Scalar.max) + overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, lhs.real) + CTAssertEqual(overflow.partialValue.imaginary, 1) + + rhs = Complex(real: Scalar.max, imaginary: 0) + overflow = lhs.componentwiseDividedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 1) + CTAssertEqual(overflow.partialValue.imaginary, lhs.imaginary) + } +} From 110527680e8173451d7c3c9257c0f039eec45aab Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Mon, 24 Feb 2020 07:15:32 -0500 Subject: [PATCH 11/13] Added `multipliedReportingOverflow`, `multipliedFullWidth`, `dividedReportingOverflow`, and `dividingFullWidth` functions --- .../ComplexOverflowingArithmetic.swift | 465 ++++++++ .../ComplexOverflowingArithmeticTests.swift | 1034 +++++++++++++++++ Tests/ComplexTests/TestingBase.swift | 18 +- 3 files changed, 1516 insertions(+), 1 deletion(-) diff --git a/Sources/Complex/ComplexOverflowingArithmetic.swift b/Sources/Complex/ComplexOverflowingArithmetic.swift index da69cce..da3de8b 100644 --- a/Sources/Complex/ComplexOverflowingArithmetic.swift +++ b/Sources/Complex/ComplexOverflowingArithmetic.swift @@ -56,6 +56,51 @@ extension Complex where Scalar: FixedWidthInteger { } } +extension Complex where Scalar: FixedWidthInteger { + + //swiftlint:disable identifier_name + public func multipliedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + // (a + bi)(c + di) = (ac − bd) + (ad + bc)i + let ac = self.real.multipliedFullWidth(by: rhs.real) + let ad = self.real.multipliedFullWidth(by: rhs.imaginary) + let bc = self.imaginary.multipliedFullWidth(by: rhs.real) + let bd = self.imaginary.multipliedFullWidth(by: rhs.imaginary) + + let real = Complex.subtract(ac, bd) + let imaginary = Complex.add(ad, bc) + + let truncatedReal = Complex.truncateAndReportOverflow(real) + let truncatedImaginary = Complex.truncateAndReportOverflow(imaginary) + + let overflow = truncatedReal.overflow || truncatedImaginary.overflow || (!Scalar.isSigned && Complex.isLess(Complex.signExtend(ac), than: Complex.signExtend(bd))) + let partialValue = Complex(real: truncatedReal.partialValue, imaginary: truncatedImaginary.partialValue) + + return (partialValue: partialValue, overflow: overflow) + } + //swiftlint:enable identifier_name +} + +extension Complex where Scalar: FixedWidthInteger, Scalar: SignedInteger { + + //swiftlint:disable identifier_name + public func multipliedFullWidth(by other: Complex) -> ExtendedComplex { + // (a + bi)(c + di) = (ac − bd) + (ad + bc)i + let ac = self.real.multipliedFullWidth(by: other.real) + let ad = self.real.multipliedFullWidth(by: other.imaginary) + let bc = self.imaginary.multipliedFullWidth(by: other.real) + let bd = self.imaginary.multipliedFullWidth(by: other.imaginary) + + let real = Complex.subtract(ac, bd) + let imaginary = Complex.add(ad, bc) + + let high = (Complex(real: real.high.high, imaginary: imaginary.high.high), Complex(real: real.high.low, imaginary: imaginary.high.low)) + let low = (Complex(real: real.low.high, imaginary: imaginary.low.high), Complex(real: real.low.low, imaginary: imaginary.low.low)) + + return (high: high, low: low) + } + //swiftlint:enable identifier_name +} + // MARK: - Overflowing Division extension Complex where Scalar: FixedWidthInteger { @@ -76,3 +121,423 @@ extension Complex where Scalar: FixedWidthInteger { return (quotient: Complex(real: real.quotient, imaginary: imaginary.quotient), remainder: Complex(real: real.remainder, imaginary: imaginary.remainder)) } } + +extension Complex where Scalar: FixedWidthInteger { + + //swiftlint:disable identifier_name + public func dividedReportingOverflow(by rhs: Complex) -> (partialValue: Complex, overflow: Bool) { + // (a + bi) / (c + di) -> ((ac + bd) + (bc - ad)i) / (c^2 + d^2) + guard rhs.real != .zero || rhs.imaginary != .zero else { return (rhs, true) } + + let ac = self.real.multipliedFullWidth(by: rhs.real) + let ad = self.real.multipliedFullWidth(by: rhs.imaginary) + let bc = self.imaginary.multipliedFullWidth(by: rhs.real) + let bd = self.imaginary.multipliedFullWidth(by: rhs.imaginary) + let cc = rhs.real.multipliedFullWidth(by: rhs.real) + let dd = rhs.imaginary.multipliedFullWidth(by: rhs.imaginary) + + let real = Complex.add(ac, bd) + let imaginary = Complex.subtract(bc, ad) + let denominator = Complex.add(cc, dd) + + let (realQuotient, _) = Complex.slowpathDivide(real, denominator) + let (imaginaryQuotient, _) = Complex.slowpathDivide(imaginary, denominator) + + let truncatedReal = Complex.truncateAndReportOverflow(realQuotient) + let truncatedImaginary = Complex.truncateAndReportOverflow(imaginaryQuotient) + + let partialValue = Complex(real: truncatedReal.partialValue, imaginary: truncatedImaginary.partialValue) + let overflow = truncatedReal.overflow || truncatedImaginary.overflow || (!Scalar.isSigned && Complex.truncateAndReportOverflow(imaginary).overflow) + + return (partialValue: partialValue, overflow: overflow) + } + //swiftlint:enable identifier_name +} + +extension Complex where Scalar: FixedWidthInteger, Scalar: SignedInteger { + + //swiftlint:disable identifier_name + public func dividingFullWidth(_ dividend: ExtendedComplex) -> (quotient: Complex, remainder: Complex) { + // (a + bi) / (c + di) -> ((ac + bd) + (bc - ad)i) / (c^2 + d^2) + let a = (high: (high: dividend.high.high.real, low: dividend.high.low.real), low: (high: dividend.low.high.real, low: dividend.low.low.real)) + let b = (high: (high: dividend.high.high.imaginary, low: dividend.high.low.imaginary), low: (high: dividend.low.high.imaginary, low: dividend.low.low.imaginary)) + + let ac = Complex.slowpathMultiply(real, a) + let ad = Complex.slowpathMultiply(imaginary, a) + let bc = Complex.slowpathMultiply(real, b) + let bd = Complex.slowpathMultiply(imaginary, b) + let cc = Complex.signExtend(real.multipliedFullWidth(by: real)) + let dd = Complex.signExtend(imaginary.multipliedFullWidth(by: imaginary)) + + let real = Complex.add(ac, bd) + let imaginary = Complex.subtract(bc, ad) + let denominator = Complex.add(cc, dd) + + let (realQuotient, realRemainder) = Complex.slowpathDivide(real, denominator) + let (imaginaryQuotient, imaginaryRemainder) = Complex.slowpathDivide(imaginary, denominator) + + let truncatedRealQuotient = Complex.truncateAndReportOverflow(realQuotient).partialValue + let truncatedImaginaryQuotient = Complex.truncateAndReportOverflow(imaginaryQuotient).partialValue + let truncatedRealRemainder = Complex.truncateAndReportOverflow(realRemainder).partialValue + let truncatedImaginaryRemainder = Complex.truncateAndReportOverflow(imaginaryRemainder).partialValue + + return (quotient: Complex(real: truncatedRealQuotient, imaginary: truncatedImaginaryQuotient), remainder: Complex(real: truncatedRealRemainder, imaginary: truncatedImaginaryRemainder)) + } + //swiftlint:enable identifier_name +} + +// MARK: Overflowing Arthimetic Helper Types & Methods + +extension Complex where Scalar: FixedWidthInteger { + + public typealias ExtendedComplex = (high: (high: Complex, low: Complex), low: (high: Complex, low: Complex)) + + internal typealias ExtendedScalar = (high: (high: Scalar, low: Scalar.Magnitude), low: (high: Scalar.Magnitude, low: Scalar.Magnitude)) + + // + + internal static func signExtend(_ value: Scalar) -> ExtendedScalar { + let highHigh = (Scalar.isSigned && value.leadingZeroBitCount == 0) ? ~Scalar.zero : Scalar.zero + let highLow = Scalar.Magnitude(truncatingIfNeeded: highHigh) + let lowHigh = Scalar.Magnitude(truncatingIfNeeded: highLow) + let lowLow = Scalar.Magnitude(truncatingIfNeeded: value) + + return (high: (high: highHigh, low: highLow), low: (high: lowHigh, low: lowLow)) + } + + internal static func signExtend(_ value: (high: Scalar, low: Scalar.Magnitude)) -> ExtendedScalar { + let highHigh = (Scalar.isSigned && value.high.leadingZeroBitCount == 0) ? ~Scalar.zero : Scalar.zero + let highLow = Scalar.Magnitude(truncatingIfNeeded: highHigh) + let lowHigh = Scalar.Magnitude(truncatingIfNeeded: value.high) + let lowLow = value.low + + return (high: (high: highHigh, low: highLow), low: (high: lowHigh, low: lowLow)) + } + + internal static func twosComplement(of value: (high: Scalar, low: Scalar.Magnitude)) -> (high: Scalar, low: Scalar.Magnitude) { + let (low, overflow) = (~value.low).addingReportingOverflow(1) + let high = (~value.high) &+ (overflow ? 1 : 0) + + return (high: high, low: low) + } + + internal static func twosComplement(of value: ExtendedScalar) -> ExtendedScalar { + let (lowLow, lowLowOverflow) = (~value.low.low).addingReportingOverflow(1) + let (lowHigh, lowHighOverflow) = (~value.low.high).addingReportingOverflow(lowLowOverflow ? 1 : 0) + let (highLow, highLowOverflow) = (~value.high.low).addingReportingOverflow(lowHighOverflow ? 1 : 0) + let highHigh = (~value.high.high) &+ (highLowOverflow ? 1 : 0) + + return (high: (high: highHigh, low: highLow), low: (high: lowHigh, low: lowLow)) + } + + // + + internal static func add(_ lhs: (high: Scalar, low: Scalar.Magnitude), _ rhs: (high: Scalar, low: Scalar.Magnitude)) -> ExtendedScalar { + return add(signExtend(lhs), signExtend(rhs)) + } + + internal static func add(_ lhs: ExtendedScalar, _ rhs: ExtendedScalar) -> ExtendedScalar { + let (lowLow, lowLowOverflow) = lhs.low.low.addingReportingOverflow(rhs.low.low) + var (lowHigh, lowHighOverflow) = lhs.low.high.addingReportingOverflow(rhs.low.high) + var (highLow, highLowOverflow) = lhs.high.low.addingReportingOverflow(rhs.high.low) + var (highHigh, _) = lhs.high.high.addingReportingOverflow(rhs.high.high) + + if lowLowOverflow { + let (value, overflow) = lowHigh.addingReportingOverflow(1) + + lowHigh = value + lowHighOverflow = lowHighOverflow || overflow + } + if lowHighOverflow { + let (value, overflow) = highLow.addingReportingOverflow(1) + + highLow = value + highLowOverflow = highLowOverflow || overflow + } + if highLowOverflow { + highHigh &+= 1 + } + + return (high: (high: highHigh, low: highLow), low: (high: lowHigh, low: lowLow)) + } + + @inline(__always) + internal static func subtract(_ lhs: (high: Scalar, low: Scalar.Magnitude), _ rhs: (high: Scalar, low: Scalar.Magnitude)) -> ExtendedScalar { + return subtract(signExtend(lhs), signExtend(rhs)) + } + + @inline(__always) + internal static func subtract(_ lhs: ExtendedScalar, _ rhs: ExtendedScalar) -> ExtendedScalar { + return add(lhs, twosComplement(of: rhs)) + } + + // + + internal static func slowpathMultiply(_ lhs: ExtendedScalar, _ rhs: ExtendedScalar) -> ExtendedScalar { + var result: ExtendedScalar = ((0, 0), (0, 0)) + + let lhsIsNegative = Scalar.isSigned && lhs.high.high < .zero + let left = lhsIsNegative ? twosComplement(of: lhs) : lhs + + let rhsIsNegative = Scalar.isSigned && rhs.high.high < .zero + let right = rhsIsNegative ? twosComplement(of: rhs) : rhs + + let (leftIsPowerOfTwo, lhsShift) = isPowerOfTwo(left) + let (rightIsPowerOfTwo, rhsShift) = isPowerOfTwo(right) + + if leftIsPowerOfTwo { + result = leftShift(right, by: lhsShift) + } else if rightIsPowerOfTwo { + result = leftShift(left, by: rhsShift) + } else { + var shift: Scalar.Magnitude = 0 + var lastShift: Scalar.Magnitude = 0 + var shifted = right + var bits = left + + while bits.low.low != .zero || bits.low.high != .zero || bits.high.low != .zero || bits.high.high != .zero { + if (bits.low.low & 1) == 1 { + shifted = leftShift(shifted, by: shift - lastShift) + result = add(result, shifted) + + lastShift = shift + } + + bits = rightShift(bits, by: 1) + shift += 1 + } + } + + if lhsIsNegative != rhsIsNegative { + result = twosComplement(of: result) + } + + return result + } + + internal static func slowpathMultiply(_ lhs: Scalar, _ rhs: ExtendedScalar) -> ExtendedScalar { + let lhsIsNegative = lhs < .zero + + let extended = signExtend(lhs) + var result = slowpathMultiply(lhsIsNegative ? twosComplement(of: extended) : extended, rhs) + + if lhsIsNegative { + result = twosComplement(of: result) + } + + return result + } + + internal static func slowpathDivide(_ lhs: ExtendedScalar, _ rhs: ExtendedScalar) -> (quotient: ExtendedScalar, remainder: ExtendedScalar) { + let dividendIsNegative = Scalar.isSigned && lhs.high.high < .zero + var dividend = dividendIsNegative ? twosComplement(of: lhs) : lhs + + let divisorIsNegative = Scalar.isSigned && rhs.high.high < .zero + var divisor = divisorIsNegative ? twosComplement(of: rhs) : rhs + + guard isLessThanOrEqual(divisor, to: dividend) else { return (quotient: ((0, 0), (0, 0)), remainder: lhs) } + let (isPowerOfTwo, shift) = self.isPowerOfTwo(divisor) + + var quotient: ExtendedScalar + var remainder: ExtendedScalar + + if isPowerOfTwo { + remainder = ((0, 0), (0, 0)) + + if shift > 0 { + // The remainder when dividing by two is equal to the bits that are going to be + // shifted out when performing the right shfit below. + + var remainderMask: ExtendedScalar = leftShift(((~0, ~0), (~0, ~0)), by: shift) + remainderMask = ((~remainderMask.high.high, ~remainderMask.high.low), (~remainderMask.low.high, ~remainderMask.low.low)) + + remainder = ((dividend.high.high & remainderMask.high.high, dividend.high.low & remainderMask.high.low), (dividend.low.high & remainderMask.low.high, dividend.low.low & remainderMask.low.low)) + } + + quotient = rightShift(dividend, by: shift) + } else { + quotient = ((0, 0), (0, 0)) + + var remainingShifts = leadingZeroBitCount(of: divisor) - leadingZeroBitCount(of: dividend) + if remainingShifts > 0 { + divisor = leftShift(divisor, by: Scalar.Magnitude(remainingShifts)) + } + + // long division + repeat { + if isLessThanOrEqual(divisor, to: dividend) { + dividend = subtract(dividend, divisor) + quotient = leftShift(quotient, by: 1) + quotient.low.low |= 1 // set least significant bit to 1 + } else { + quotient = leftShift(quotient, by: 1) + } + + divisor = rightShift(divisor, by: 1) + remainingShifts -= 1 + } while remainingShifts >= 0 + + remainder = dividend + } + + if dividendIsNegative != divisorIsNegative { + quotient = twosComplement(of: quotient) + } + if dividendIsNegative { + remainder = twosComplement(of: remainder) + } + + return (quotient: quotient, remainder: remainder) + } + + // + + internal static func leftShift(_ value: ExtendedScalar, by shiftAmount: Scalar.Magnitude) -> ExtendedScalar { + guard shiftAmount < Scalar.bitWidth * 4 else { return ((0, 0), (0, 0)) } + + let shiftMask = Scalar.bitWidth - 1 + var result = value + for _ in 0 ..< shiftAmount { + result.high.high = Scalar(truncatingIfNeeded: (Scalar.Magnitude(truncatingIfNeeded: result.high.high) &<< 1) | (result.high.low &>> shiftMask)) + result.high.low = (result.high.low &<< 1) | (result.low.high &>> shiftMask) + result.low.high = (result.low.high &<< 1) | (result.low.low &>> shiftMask) + result.low.low &<<= 1 + } + + return result + } + + internal static func rightShift(_ value: ExtendedScalar, by shiftAmount: Scalar.Magnitude) -> ExtendedScalar { + guard shiftAmount < Scalar.bitWidth * 4 else { return ((0, 0), (0, 0)) } + + let shiftMask = Scalar.bitWidth - 1 + var result = value + for _ in 0 ..< shiftAmount { + result.low.low = (result.low.low &>> 1) | (result.low.high &<< shiftMask) + result.low.high = (result.low.high &>> 1) | (result.high.low &<< shiftMask) + result.high.low = (result.high.low &>> 1) | (Scalar.Magnitude(truncatingIfNeeded: result.high.high) &<< shiftMask) + result.high.high = Scalar(truncatingIfNeeded: Scalar.Magnitude(truncatingIfNeeded: result.high.high) &>> 1) + } + + return result + } + + // + + internal static func isLessThanOrEqual(_ lhs: ExtendedScalar, to rhs: ExtendedScalar) -> Bool { + let isLessThanOrEqual: Bool + + if lhs.high.high == rhs.high.high { + if lhs.high.low == rhs.high.low { + if lhs.low.high == rhs.low.high { + isLessThanOrEqual = (lhs.low.low <= rhs.low.low) + } else { + isLessThanOrEqual = (lhs.low.high <= rhs.low.high) + } + } else { + isLessThanOrEqual = (lhs.high.low <= rhs.high.low) + } + } else { + isLessThanOrEqual = (lhs.high.high <= rhs.high.high) + } + + return isLessThanOrEqual + } + + internal static func isLess(_ lhs: ExtendedScalar, than rhs: ExtendedScalar) -> Bool { + let isLessThanOrEqual: Bool + + if lhs.high.high == rhs.high.high { + if lhs.high.low == rhs.high.low { + if lhs.low.high == rhs.low.high { + isLessThanOrEqual = (lhs.low.low < rhs.low.low) + } else { + isLessThanOrEqual = (lhs.low.high < rhs.low.high) + } + } else { + isLessThanOrEqual = (lhs.high.low < rhs.high.low) + } + } else { + isLessThanOrEqual = (lhs.high.high < rhs.high.high) + } + + return isLessThanOrEqual + } + + internal static func isPowerOfTwo(_ value: ExtendedScalar) -> (isPowerOfTwo: Bool, power: Scalar.Magnitude) { + if (value.high.high.nonzeroBitCount + value.high.low.nonzeroBitCount + value.low.high.nonzeroBitCount + value.low.low.nonzeroBitCount) == 1 { + var bits = value + var shift: Scalar.Magnitude = 0 + + while bits.low.low > 1 || bits.low.high != .zero || bits.high.low != .zero || bits.high.high != .zero { + bits = rightShift(bits, by: 1) + shift += 1 + } + + return (true, shift) + } + + return (false, 0) + } + + internal static func leadingZeroBitCount(of value: ExtendedScalar) -> Int { + let bitWidth = Scalar.bitWidth + var leadingZeroBitCount = value.high.high.leadingZeroBitCount + + if leadingZeroBitCount == bitWidth { + leadingZeroBitCount += value.high.low.leadingZeroBitCount + + if leadingZeroBitCount == (bitWidth * 2) { + leadingZeroBitCount += value.low.high.leadingZeroBitCount + + if leadingZeroBitCount == (bitWidth * 3) { + leadingZeroBitCount += value.low.low.leadingZeroBitCount + } + } + } + + return leadingZeroBitCount + } + + // + + internal static func truncateAndReportOverflow(_ value: ExtendedScalar) -> (partialValue: Scalar, overflow: Bool) { + // Return value doesn't change. + let partialValue = Scalar(truncatingIfNeeded: value.low.low) + + // Check for overflow + var overflow: Bool = false + + if Scalar.isSigned { + // For signed integers we have different logic depending on if the input is + // negative or positive: + // + // Negative: Overflow occurs when any of the bits of any of the three most + // significant words are zero or if the most significant bit of + // the least significant word is 0. + // + // Positive: Overflow occurs when the any of the three most significant words are + // non-zero or if the most significant bit of the least significant word + // is 1. + + if value.high.high < .zero { + if value.high.high.nonzeroBitCount != Scalar.bitWidth || value.high.low.nonzeroBitCount != Scalar.bitWidth || value.low.high.nonzeroBitCount != Scalar.bitWidth { + overflow = true + } else if value.low.low.leadingZeroBitCount > 0 { + overflow = true + } + } else if value.high.high != .zero || value.high.low != .zero || value.low.high != .zero { + overflow = true + } else if value.low.low.leadingZeroBitCount == 0 { + overflow = true + } + } else { + // For unsigned integers overflow occurs when the any of the three most significant + // words are non-zero. + + overflow = (value.high.high > .zero) || (value.high.low > .zero) || (value.low.high > .zero) + } + + return (partialValue, overflow) + } +} diff --git a/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift b/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift index c3339fa..008e6cb 100644 --- a/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift +++ b/Tests/ComplexTests/ComplexOverflowingArithmeticTests.swift @@ -64,6 +64,219 @@ class ComplexOverflowingArithmeticTests: XCTestCase { testComponentwiseOverflowingDivision(forType: UInt.self) } + func testMultiplyReportingOverflow() { + testMultiplyReportingOverflow(forType: Int8.self) + testMultiplyReportingOverflow(forType: Int16.self) + testMultiplyReportingOverflow(forType: Int32.self) + testMultiplyReportingOverflow(forType: Int64.self) + testMultiplyReportingOverflow(forType: Int.self) + testMultiplyReportingOverflow(forType: UInt8.self) + testMultiplyReportingOverflow(forType: UInt16.self) + testMultiplyReportingOverflow(forType: UInt32.self) + testMultiplyReportingOverflow(forType: UInt64.self) + testMultiplyReportingOverflow(forType: UInt.self) + } + + func testMultiplyFullWidth() { + testMultiplyFullWidth(forType: Int8.self) + testMultiplyFullWidth(forType: Int16.self) + testMultiplyFullWidth(forType: Int32.self) + testMultiplyFullWidth(forType: Int64.self) + testMultiplyFullWidth(forType: Int.self) + } + + func testDivideReportingOverflow() { + testDivideReportingOverflow(forType: Int8.self) + testDivideReportingOverflow(forType: Int16.self) + testDivideReportingOverflow(forType: Int32.self) + testDivideReportingOverflow(forType: Int64.self) + testDivideReportingOverflow(forType: Int.self) + testDivideReportingOverflow(forType: UInt8.self) + testDivideReportingOverflow(forType: UInt16.self) + testDivideReportingOverflow(forType: UInt32.self) + testDivideReportingOverflow(forType: UInt64.self) + testDivideReportingOverflow(forType: UInt.self) + } + + func testDivideFullWidth() { + testDivideFullWidth(forType: Int8.self) + testDivideFullWidth(forType: Int16.self) + testDivideFullWidth(forType: Int32.self) + testDivideFullWidth(forType: Int64.self) + testDivideFullWidth(forType: Int.self) + } + + // + + func testSignExtension() { + testSignExtension(forType: Int8.self) + testSignExtension(forType: Int16.self) + testSignExtension(forType: Int32.self) + testSignExtension(forType: Int64.self) + testSignExtension(forType: Int.self) + testSignExtension(forType: UInt8.self) + testSignExtension(forType: UInt16.self) + testSignExtension(forType: UInt32.self) + testSignExtension(forType: UInt64.self) + testSignExtension(forType: UInt.self) + } + + func testTwosComplement() { + testTwosComplement(forType: Int8.self) + testTwosComplement(forType: Int16.self) + testTwosComplement(forType: Int32.self) + testTwosComplement(forType: Int64.self) + testTwosComplement(forType: Int.self) + testTwosComplement(forType: UInt8.self) + testTwosComplement(forType: UInt16.self) + testTwosComplement(forType: UInt32.self) + testTwosComplement(forType: UInt64.self) + testTwosComplement(forType: UInt.self) + } + + func testAddExtendedScalars() { + testAddExtendedScalars(forType: Int8.self) + testAddExtendedScalars(forType: Int16.self) + testAddExtendedScalars(forType: Int32.self) + testAddExtendedScalars(forType: Int64.self) + testAddExtendedScalars(forType: Int.self) + testAddExtendedScalars(forType: UInt8.self) + testAddExtendedScalars(forType: UInt16.self) + testAddExtendedScalars(forType: UInt32.self) + testAddExtendedScalars(forType: UInt64.self) + testAddExtendedScalars(forType: UInt.self) + } + + func testSubtractExtendedScalars() { + testSubtractExtendedScalars(forType: Int8.self) + testSubtractExtendedScalars(forType: Int16.self) + testSubtractExtendedScalars(forType: Int32.self) + testSubtractExtendedScalars(forType: Int64.self) + testSubtractExtendedScalars(forType: Int.self) + testSubtractExtendedScalars(forType: UInt8.self) + testSubtractExtendedScalars(forType: UInt16.self) + testSubtractExtendedScalars(forType: UInt32.self) + testSubtractExtendedScalars(forType: UInt64.self) + testSubtractExtendedScalars(forType: UInt.self) + } + + func testLeftShiftExtendedScalars() { + testLeftShiftExtendedScalars(forType: Int8.self) + testLeftShiftExtendedScalars(forType: Int16.self) + testLeftShiftExtendedScalars(forType: Int32.self) + testLeftShiftExtendedScalars(forType: Int64.self) + testLeftShiftExtendedScalars(forType: Int.self) + testLeftShiftExtendedScalars(forType: UInt8.self) + testLeftShiftExtendedScalars(forType: UInt16.self) + testLeftShiftExtendedScalars(forType: UInt32.self) + testLeftShiftExtendedScalars(forType: UInt64.self) + testLeftShiftExtendedScalars(forType: UInt.self) + } + + func testRightShiftExtendedScalars() { + testRightShiftExtendedScalars(forType: Int8.self) + testRightShiftExtendedScalars(forType: Int16.self) + testRightShiftExtendedScalars(forType: Int32.self) + testRightShiftExtendedScalars(forType: Int64.self) + testRightShiftExtendedScalars(forType: Int.self) + testRightShiftExtendedScalars(forType: UInt8.self) + testRightShiftExtendedScalars(forType: UInt16.self) + testRightShiftExtendedScalars(forType: UInt32.self) + testRightShiftExtendedScalars(forType: UInt64.self) + testRightShiftExtendedScalars(forType: UInt.self) + } + + func testIsLessThanOrEqual() { + testIsLessThanOrEqual(forType: Int8.self) + testIsLessThanOrEqual(forType: Int16.self) + testIsLessThanOrEqual(forType: Int32.self) + testIsLessThanOrEqual(forType: Int64.self) + testIsLessThanOrEqual(forType: Int.self) + testIsLessThanOrEqual(forType: UInt8.self) + testIsLessThanOrEqual(forType: UInt16.self) + testIsLessThanOrEqual(forType: UInt32.self) + testIsLessThanOrEqual(forType: UInt64.self) + testIsLessThanOrEqual(forType: UInt.self) + } + + func testIsLessThan() { + testIsLessThan(forType: Int8.self) + testIsLessThan(forType: Int16.self) + testIsLessThan(forType: Int32.self) + testIsLessThan(forType: Int64.self) + testIsLessThan(forType: Int.self) + testIsLessThan(forType: UInt8.self) + testIsLessThan(forType: UInt16.self) + testIsLessThan(forType: UInt32.self) + testIsLessThan(forType: UInt64.self) + testIsLessThan(forType: UInt.self) + } + + func testIsPowerOfTwo() { + testIsPowerOfTwo(forType: Int8.self) + testIsPowerOfTwo(forType: Int16.self) + testIsPowerOfTwo(forType: Int32.self) + testIsPowerOfTwo(forType: Int64.self) + testIsPowerOfTwo(forType: Int.self) + testIsPowerOfTwo(forType: UInt8.self) + testIsPowerOfTwo(forType: UInt16.self) + testIsPowerOfTwo(forType: UInt32.self) + testIsPowerOfTwo(forType: UInt64.self) + testIsPowerOfTwo(forType: UInt.self) + } + + func testLeadingZeroBitCount() { + testLeadingZeroBitCount(forType: Int8.self) + testLeadingZeroBitCount(forType: Int16.self) + testLeadingZeroBitCount(forType: Int32.self) + testLeadingZeroBitCount(forType: Int64.self) + testLeadingZeroBitCount(forType: Int.self) + testLeadingZeroBitCount(forType: UInt8.self) + testLeadingZeroBitCount(forType: UInt16.self) + testLeadingZeroBitCount(forType: UInt32.self) + testLeadingZeroBitCount(forType: UInt64.self) + testLeadingZeroBitCount(forType: UInt.self) + } + + func testTruncateExtendedScalars() { + testTruncateExtendedScalars(forType: Int8.self) + testTruncateExtendedScalars(forType: Int16.self) + testTruncateExtendedScalars(forType: Int32.self) + testTruncateExtendedScalars(forType: Int64.self) + testTruncateExtendedScalars(forType: Int.self) + testTruncateExtendedScalars(forType: UInt8.self) + testTruncateExtendedScalars(forType: UInt16.self) + testTruncateExtendedScalars(forType: UInt32.self) + testTruncateExtendedScalars(forType: UInt64.self) + testTruncateExtendedScalars(forType: UInt.self) + } + + func testSlowpathMultiply() { + testSlowpathMultiply(forType: Int8.self) + testSlowpathMultiply(forType: Int16.self) + testSlowpathMultiply(forType: Int32.self) + testSlowpathMultiply(forType: Int64.self) + testSlowpathMultiply(forType: Int.self) + testSlowpathMultiply(forType: UInt8.self) + testSlowpathMultiply(forType: UInt16.self) + testSlowpathMultiply(forType: UInt32.self) + testSlowpathMultiply(forType: UInt64.self) + testSlowpathMultiply(forType: UInt.self) + } + + func testSlowpathDivide() { + testSlowpathDivide(forType: Int8.self) + testSlowpathDivide(forType: Int16.self) + testSlowpathDivide(forType: Int32.self) + testSlowpathDivide(forType: Int64.self) + testSlowpathDivide(forType: Int.self) + testSlowpathDivide(forType: UInt8.self) + testSlowpathDivide(forType: UInt16.self) + testSlowpathDivide(forType: UInt32.self) + testSlowpathDivide(forType: UInt64.self) + testSlowpathDivide(forType: UInt.self) + } + // MARK: Private Methods private func testOverflowingAddition(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: UnsignedInteger { @@ -234,4 +447,825 @@ class ComplexOverflowingArithmeticTests: XCTestCase { CTAssertEqual(overflow.partialValue.real, 1) CTAssertEqual(overflow.partialValue.imaginary, lhs.imaginary) } + + private func testMultiplyReportingOverflow(forType: Scalar.Type) where Scalar: FixedWidthInteger { + if Scalar.isSigned { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 4, imaginary: 4) + + var overflow = lhs.multipliedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 0) + CTAssertEqual(overflow.partialValue.imaginary, -8) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 4, imaginary: 0) + overflow = lhs.multipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, -4) + CTAssertEqual(overflow.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 4) + overflow = lhs.multipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 4) + CTAssertEqual(overflow.partialValue.imaginary, 0) + + lhs = Complex(real: -10, imaginary: 4) + rhs = Complex(real: -10, imaginary: 3) + overflow = lhs.multipliedReportingOverflow(by: rhs) + + CTAssertFalse(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 88) + CTAssertEqual(overflow.partialValue.imaginary, -70) + } else { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 2, imaginary: 2) + + var overflow = lhs.multipliedReportingOverflow(by: rhs) + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 0) + CTAssertEqual(overflow.partialValue.imaginary, Scalar.max &<< 2) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 2, imaginary: 0) + overflow = lhs.multipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, Scalar.max - 1) + CTAssertEqual(overflow.partialValue.imaginary, 0) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 2) + overflow = lhs.multipliedReportingOverflow(by: rhs) + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 2) + CTAssertEqual(overflow.partialValue.imaginary, 0) + + lhs = Complex(real: 10, imaginary: 4) + rhs = Complex(real: 10, imaginary: 3) + overflow = lhs.multipliedReportingOverflow(by: rhs) + + CTAssertFalse(overflow.overflow) + CTAssertEqual(overflow.partialValue.real, 88) + CTAssertEqual(overflow.partialValue.imaginary, 70) + } + } + + private func testMultiplyFullWidth(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: SignedInteger { + var lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + var rhs = Complex(real: 8, imaginary: 4) + var fullWidth = lhs.multipliedFullWidth(by: rhs) + var real = ((fullWidth.high.high.real, fullWidth.high.low.real), (fullWidth.low.high.real, fullWidth.low.low.real)) + var imaginary = ((fullWidth.high.high.imaginary, fullWidth.high.low.imaginary), (fullWidth.low.high.imaginary, fullWidth.low.low.imaginary)) + + CTAssertEqual(real, ((0, 0), (1, Scalar.Magnitude.max &<< 2))) + CTAssertEqual(imaginary, ((0, 0), (5, Scalar.max.multipliedFullWidth(by: 12).low))) + + lhs = Complex(real: Scalar.max, imaginary: 0) + rhs = Complex(real: 4, imaginary: 0) + fullWidth = lhs.multipliedFullWidth(by: rhs) + real = ((fullWidth.high.high.real, fullWidth.high.low.real), (fullWidth.low.high.real, fullWidth.low.low.real)) + imaginary = ((fullWidth.high.high.imaginary, fullWidth.high.low.imaginary), (fullWidth.low.high.imaginary, fullWidth.low.low.imaginary)) + + CTAssertEqual(real, ((0, 0), (1, Scalar.Magnitude.max &<< 2))) + CTAssertEqual(imaginary, ((0, 0), (0, 0))) + + lhs = Complex(real: 0, imaginary: Scalar.max) + rhs = Complex(real: 0, imaginary: 4) + fullWidth = lhs.multipliedFullWidth(by: rhs) + real = ((fullWidth.high.high.real, fullWidth.high.low.real), (fullWidth.low.high.real, fullWidth.low.low.real)) + imaginary = ((fullWidth.high.high.imaginary, fullWidth.high.low.imaginary), (fullWidth.low.high.imaginary, fullWidth.low.low.imaginary)) + + CTAssertEqual(real, ((~0, ~0), (Scalar.Magnitude.max - 1, 4))) + CTAssertEqual(imaginary, ((0, 0), (0, 0))) + + lhs = Complex(real: -10, imaginary: 4) + rhs = Complex(real: -10, imaginary: 3) + fullWidth = lhs.multipliedFullWidth(by: rhs) + real = ((fullWidth.high.high.real, fullWidth.high.low.real), (fullWidth.low.high.real, fullWidth.low.low.real)) + imaginary = ((fullWidth.high.high.imaginary, fullWidth.high.low.imaginary), (fullWidth.low.high.imaginary, fullWidth.low.low.imaginary)) + + CTAssertEqual(real, ((0, 0), (0, 88))) + CTAssertEqual(imaginary, ((~0, ~0), (~0, Scalar.Magnitude(truncatingIfNeeded: Scalar(-70))))) + } + + private func testDivideReportingOverflow(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var lhs = Complex(real: Scalar.random(in: Scalar.min ... Scalar.max), imaginary: Scalar.random(in: Scalar.min ... Scalar.max)) + var rhs = Complex(real: 0, imaginary: 0) + var overflow = lhs.dividedReportingOverflow(by: rhs) // divide by 0 + + CTAssertTrue(overflow.overflow) + CTAssertEqual(overflow.partialValue, rhs) + + lhs = Complex(real: 11, imaginary: 9) + rhs = Complex(real: 7, imaginary: 3) + overflow = lhs.dividedReportingOverflow(by: rhs) + + CTAssertFalse(overflow.overflow) + CTAssertEqual(overflow.partialValue, Complex(real: 1, imaginary: 0)) + + lhs = Complex(real: 11, imaginary: 9) + rhs = Complex(real: 3, imaginary: 7) + overflow = lhs.dividedReportingOverflow(by: rhs) + + CTAssertEqual(overflow.overflow, !Scalar.isSigned) + CTAssertEqual(overflow.partialValue.real, 1) + + if Scalar.isSigned { + CTAssertEqual(overflow.partialValue.imaginary, 0) + } + + lhs = Complex(real: Scalar.max, imaginary: Scalar.max) + rhs = Complex(real: 4, imaginary: 4) + overflow = lhs.dividedReportingOverflow(by: rhs) + + CTAssertFalse(overflow.overflow) + CTAssertEqual(overflow.partialValue, Complex(real: Scalar.max &>> 2, imaginary: 0)) + } + + private func testDivideFullWidth(forType: Scalar.Type) where Scalar: FixedWidthInteger, Scalar: SignedInteger { + var lhs = Complex(real: 7, imaginary: 3) + var rhs: Complex.ExtendedComplex = ((.zero, .zero), (.zero, Complex(real: 11, imaginary: 9))) + var fullWidth = lhs.dividingFullWidth(rhs) + + CTAssertEqual(fullWidth.quotient, Complex(real: 1, imaginary: 0)) + CTAssertEqual(fullWidth.remainder, Complex(real: 46, imaginary: 30)) + + lhs = Complex(real: 3, imaginary: 7) + fullWidth = lhs.dividingFullWidth(rhs) + + CTAssertEqual(fullWidth.quotient, Complex(real: 1, imaginary: 0)) + CTAssertEqual(fullWidth.remainder, Complex(real: 38, imaginary: -50)) + + lhs = Complex(real: 4, imaginary: 4) + rhs = ((.zero, .zero), (.zero, Complex(real: Scalar.Magnitude(Scalar.max), imaginary: Scalar.Magnitude(Scalar.max)))) + fullWidth = lhs.dividingFullWidth(rhs) + + CTAssertEqual(fullWidth.quotient, Complex(real: Scalar.max &>> 2, imaginary: 0)) + CTAssertEqual(fullWidth.remainder, Complex(real: 24, imaginary: 0)) + } + + // + + private func testSignExtension(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var value = Scalar.min.multipliedFullWidth(by: 1) + var extended = Complex.signExtend(value) + CTAssertEqual(extended, (high: (high: Scalar.isSigned ? ~0 : 0, low: Scalar.isSigned ? Scalar.Magnitude.max : 0), low: (high: Scalar.Magnitude(truncatingIfNeeded: value.high), low: value.low))) + + extended = Complex.signExtend(Scalar.min) + CTAssertEqual(extended, (high: (high: Scalar.isSigned ? ~0 : 0, low: Scalar.isSigned ? Scalar.Magnitude.max : 0), low: (high: Scalar.Magnitude(truncatingIfNeeded: value.high), low: value.low))) + + value = Scalar.max.multipliedFullWidth(by: 1) + extended = Complex.signExtend(value) + CTAssertEqual(extended, (high: (high: 0, low: 0), low: (high: Scalar.Magnitude(truncatingIfNeeded: value.high), low: value.low))) + + extended = Complex.signExtend(Scalar.max) + CTAssertEqual(extended, (high: (high: 0, low: 0), low: (high: Scalar.Magnitude(truncatingIfNeeded: value.high), low: value.low))) + + extended = Complex.signExtend((0, 0)) + CTAssertEqual(extended, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + extended = Complex.signExtend(Scalar.zero) + CTAssertEqual(extended, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + value = (Scalar.max, Scalar.Magnitude.max) + extended = Complex.signExtend(value) + CTAssertEqual(extended, (high: (high: 0, low: 0), low: (high: Scalar.Magnitude(truncatingIfNeeded: value.high), low: value.low))) + } + + private func testTwosComplement(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var value2: (high: Scalar, low: Scalar.Magnitude) = (0, 0) + var complement2 = Complex.twosComplement(of: value2) + CTAssertEqual(complement2.high, value2.high) + CTAssertEqual(complement2.low, value2.low) + + value2 = (~0, 0) + complement2 = Complex.twosComplement(of: value2) + CTAssertEqual(complement2.high, 1) + CTAssertEqual(complement2.low, value2.low) + + value2 = (0, 1) + complement2 = Complex.twosComplement(of: value2) + CTAssertEqual(complement2.high, ~0) + CTAssertEqual(complement2.low, ~0) + + // + + var extendedValue: Complex.ExtendedScalar = ((0, 0), (0, 0)) + var extendedComplement = Complex.twosComplement(of: extendedValue) + CTAssertEqual(extendedComplement, extendedValue) + + extendedValue = ((~0, 0), (0, 0)) + extendedComplement = Complex.twosComplement(of: extendedValue) + CTAssertEqual(extendedComplement, (high: (high: 1, low: 0), low: (high: 0, low: 0))) + + extendedValue = ((0, 0), (0, 1)) + extendedComplement = Complex.twosComplement(of: extendedValue) + CTAssertEqual(extendedComplement, (high: (high: ~0, low: ~0), low: (high: ~0, low: ~0))) + } + + private func testAddExtendedScalars(forType: Scalar.Type) where Scalar: FixedWidthInteger { + // Test: 0 + 0 = 0 + // + var nonextendedLHS: (high: Scalar, low: Scalar.Magnitude) = (high: 0, low: 0) + var nonextendedRHS: (high: Scalar, low: Scalar.Magnitude) = (high: 0, low: 0) + var result = Complex.add(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + var extendedLHS = Complex.signExtend(nonextendedLHS) + var extendedRHS = Complex.signExtend(nonextendedRHS) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + // Test overflow of `low.low` + // + nonextendedLHS = (high: 0, low: 1) + nonextendedRHS = (high: 0, low: Scalar.Magnitude.max) + result = Complex.add(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 1, low: 0))) + + extendedLHS = Complex.signExtend(nonextendedLHS) + extendedRHS = Complex.signExtend(nonextendedRHS) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 1, low: 0))) + + // Test non-overflow of `low.low` + // + nonextendedLHS = (high: 0, low: 1) + nonextendedRHS = (high: 0, low: Scalar.Magnitude.max - 1) + result = Complex.add(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: Scalar.Magnitude.max))) + + extendedLHS = Complex.signExtend(nonextendedLHS) + extendedRHS = Complex.signExtend(nonextendedRHS) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: Scalar.Magnitude.max))) + + // Test overflow of `low.high` + // + nonextendedLHS = (high: 1, low: 0) + nonextendedRHS = (high: ~Scalar.zero, low: Scalar.Magnitude.max) + result = Complex.add(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: 0, low: Scalar.isSigned ? 0 : 1), low: (high: 0, low: Scalar.Magnitude.max))) + + extendedLHS = Complex.signExtend(nonextendedLHS) + extendedRHS = Complex.signExtend(nonextendedRHS) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: Scalar.isSigned ? 0 : 1), low: (high: 0, low: Scalar.Magnitude.max))) + + // Test non-overflow of `low.high` + // + nonextendedLHS = (high: 1, low: 0) + nonextendedRHS = (high: ~Scalar.zero - 1, low: 0) + result = Complex.add(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: Scalar.isSigned ? ~Scalar.zero : 0, low: Scalar.isSigned ? ~Scalar.Magnitude.zero : 0), low: (high: ~Scalar.Magnitude.zero, low: 0))) + + extendedLHS = Complex.signExtend(nonextendedLHS) + extendedRHS = Complex.signExtend(nonextendedRHS) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: Scalar.isSigned ? ~Scalar.zero : 0, low: Scalar.isSigned ? ~Scalar.Magnitude.zero : 0), low: (high: ~Scalar.Magnitude.zero, low: 0))) + + // Test overflow of `low.high` from overflow of `low.low` + // + nonextendedLHS = (high: 1, low: 1) + nonextendedRHS = (high: ~Scalar.zero - 1, low: Scalar.Magnitude.max) + result = Complex.add(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: 0, low: Scalar.isSigned ? 0 : 1), low: (high: 0, low: 0))) + + extendedLHS = Complex.signExtend(nonextendedLHS) + extendedRHS = Complex.signExtend(nonextendedRHS) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: Scalar.isSigned ? 0 : 1), low: (high: 0, low: 0))) + + // Test overflow of `high.low` + // + extendedLHS = (high: (high: 0, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: 0, low: Scalar.Magnitude.max), (high: 0, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 1, low: 0), low: (high: 1, low: 1))) + + // Test non-overflow of `high.low` + // + extendedLHS = (high: (high: 0, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: 0, low: Scalar.Magnitude.max - 1), (high: 0, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: Scalar.Magnitude.max), low: (high: 1, low: 1))) + + // Test overflow of `high.low` from overflow of `low.high` + // + extendedLHS = (high: (high: 0, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: 0, low: Scalar.Magnitude.max - 1), (high: Scalar.Magnitude.max, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 1, low: 0), low: (high: 0, low: 1))) + + // Test overflow of `high.low` from overflow of `low.high` from overflow of `low.low` + // + extendedLHS = (high: (high: 0, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: 0, low: Scalar.Magnitude.max - 1), (high: Scalar.Magnitude.max - 1, low: Scalar.Magnitude.max)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 1, low: 0), low: (high: 0, low: 0))) + + // Test overflow of `high.high` + // + extendedLHS = (high: (high: 1, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: ~Scalar.zero, low: 0), (high: 0, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 1), low: (high: 1, low: 1))) + + // Test non-overflow of `high.high` + // + extendedLHS = (high: (high: 1, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: ~Scalar.zero - 1, low: 0), (high: 0, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: ~Scalar.zero, low: 1), low: (high: 1, low: 1))) + + // Test overflow of `high.high` from overflow of `high.low` + // + extendedLHS = (high: (high: 1, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: ~Scalar.zero - 1, low: Scalar.Magnitude.max), (high: 0, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 1, low: 1))) + + // Test overflow of `high.high` from overflow of `high.low` from overflow of `low.high` + // + extendedLHS = (high: (high: 1, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: ~Scalar.zero - 1, low: Scalar.Magnitude.max - 1), (high: Scalar.Magnitude.max, low: 0)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 1))) + + // Test overflow of `high.high` from overflow of `high.low` from overflow of `low.high` from overflow of `low.low` + // + extendedLHS = (high: (high: 1, low: 1), (high: 1, low: 1)) + extendedRHS = (high: (high: ~Scalar.zero - 1, low: Scalar.Magnitude.max - 1), (high: Scalar.Magnitude.max - 1, low: Scalar.Magnitude.max)) + result = Complex.add(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + } + + private func testSubtractExtendedScalars(forType: Scalar.Type) where Scalar: FixedWidthInteger { + // Test x - 0 = x + // + var nonextendedLHS: (high: Scalar, low: Scalar.Magnitude) = (3, Scalar.Magnitude.max) + var nonextendedRHS: (high: Scalar, low: Scalar.Magnitude) = (0, 0) + var result = Complex.subtract(nonextendedLHS, nonextendedRHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 3, low: Scalar.Magnitude.max))) + + var extendedLHS: Complex.ExtendedScalar = ((1, Scalar.Magnitude.max &>> 1), (3, Scalar.Magnitude.max)) + var extendedRHS: Complex.ExtendedScalar = ((0, 0), (0, 0)) + result = Complex.subtract(extendedLHS, extendedRHS) + CTAssertEqual(result, (high: (high: 1, low: Scalar.Magnitude.max &>> 1), low: (high: 3, low: Scalar.Magnitude.max))) + + if Scalar.isSigned { + // Test 0 - x = -x + // + nonextendedLHS = (0, 0) + nonextendedRHS = (3, Scalar.Magnitude.max) + result = Complex.twosComplement(of: Complex.subtract(nonextendedLHS, nonextendedRHS)) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 3, low: Scalar.Magnitude.max))) + + extendedLHS = ((0, 0), (0, 0)) + extendedRHS = ((1, Scalar.Magnitude.max &>> 1), (3, Scalar.Magnitude.max)) + result = Complex.twosComplement(of: Complex.subtract(extendedLHS, extendedRHS)) + CTAssertEqual(result, (high: (high: 1, low: Scalar.Magnitude.max &>> 1), low: (high: 3, low: Scalar.Magnitude.max))) + } + + // Test x - x = 0 + // + nonextendedLHS = (3, Scalar.Magnitude.max) + result = Complex.subtract(nonextendedLHS, nonextendedLHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + extendedLHS = ((1, Scalar.Magnitude.max >> 1), (3, Scalar.Magnitude.max)) + result = Complex.subtract(extendedLHS, extendedLHS) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + } + + private func testLeftShiftExtendedScalars(forType: Scalar.Type) where Scalar: FixedWidthInteger { + let upperHalf = (~Scalar.Magnitude.zero) &<< (Scalar.Magnitude.bitWidth / 2) + let lowerHalf = (~Scalar.Magnitude.zero) &>> (Scalar.Magnitude.bitWidth / 2) + let shiftedUpperHalf = (upperHalf &<< 1) + 1 + + var value: Complex.ExtendedScalar = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + var result = Complex.leftShift(value, by: 1) + CTAssertEqual(result, (high: (high: ~Scalar.zero, low: Scalar.Magnitude.max), low: (high: Scalar.Magnitude.max, low: Scalar.Magnitude.max - 1))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth)) + CTAssertEqual(result, (high: (high: ~Scalar.zero, low: Scalar.Magnitude.max), low: (high: Scalar.Magnitude.max, low: 0))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth / 2)) + CTAssertEqual(result, (high: (high: ~Scalar.zero, low: Scalar.Magnitude.max), low: (high: Scalar.Magnitude.max, low: upperHalf))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth * 2)) + CTAssertEqual(result, (high: (high: ~Scalar.zero, low: Scalar.Magnitude.max), low: (high: 0, low: 0))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth * 3)) + CTAssertEqual(result, (high: (high: ~Scalar.zero, low: 0), low: (high: 0, low: 0))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth * 4)) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + value = ((Scalar(truncatingIfNeeded: upperHalf), upperHalf), (upperHalf, upperHalf)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth / 2)) + CTAssertEqual(result, (high: (high: Scalar(truncatingIfNeeded: lowerHalf), low: lowerHalf), low: (high: lowerHalf, low: 0))) + + value = ((Scalar(truncatingIfNeeded: lowerHalf), lowerHalf), (lowerHalf, lowerHalf)) + result = Complex.leftShift(value, by: Scalar.Magnitude(Scalar.bitWidth / 2)) + CTAssertEqual(result, (high: (high: Scalar(truncatingIfNeeded: upperHalf), low: upperHalf), low: (high: upperHalf, low: upperHalf))) + + value = ((Scalar(truncatingIfNeeded: upperHalf), upperHalf), (upperHalf, upperHalf)) + result = Complex.leftShift(value, by: 1) + CTAssertEqual(result, (high: (high: Scalar(truncatingIfNeeded: shiftedUpperHalf), low: shiftedUpperHalf), low: (high: shiftedUpperHalf, low: upperHalf &<< 1))) + } + + private func testRightShiftExtendedScalars(forType: Scalar.Type) where Scalar: FixedWidthInteger { + let upperHalf = (~Scalar.Magnitude.zero) &<< (Scalar.Magnitude.bitWidth / 2) + let lowerHalf = (~Scalar.Magnitude.zero) &>> (Scalar.Magnitude.bitWidth / 2) + let shiftedLowerHalf = (lowerHalf &>> 1) | upperHalf &<< ((Scalar.Magnitude.bitWidth / 2) - 1) + + var value: Complex.ExtendedScalar = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + var result = Complex.rightShift(value, by: 1) + CTAssertEqual(result, (high: (high: Scalar.max &>> (Scalar.isSigned ? 0 : 1), low: Scalar.Magnitude.max), low: (high: Scalar.Magnitude.max, low: Scalar.Magnitude.max))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth)) + CTAssertEqual(result, (high: (high: 0, low: Scalar.Magnitude.max), low: (high: Scalar.Magnitude.max, low: Scalar.Magnitude.max))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth / 2)) + CTAssertEqual(result, (high: (high: Scalar(truncatingIfNeeded: lowerHalf), low: Scalar.Magnitude.max), low: (high: Scalar.Magnitude.max, low: Scalar.Magnitude.max))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth * 2)) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: Scalar.Magnitude.max, low: Scalar.Magnitude.max))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth * 3)) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: Scalar.Magnitude.max))) + + value = ((~Scalar.zero, Scalar.Magnitude.max), (Scalar.Magnitude.max, Scalar.Magnitude.max)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth * 4)) + CTAssertEqual(result, (high: (high: 0, low: 0), low: (high: 0, low: 0))) + + value = ((Scalar(truncatingIfNeeded: upperHalf), upperHalf), (upperHalf, upperHalf)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth / 2)) + CTAssertEqual(result, (high: (high: Scalar(truncatingIfNeeded: lowerHalf), low: lowerHalf), low: (high: lowerHalf, low: lowerHalf))) + + value = ((Scalar(truncatingIfNeeded: lowerHalf), lowerHalf), (lowerHalf, lowerHalf)) + result = Complex.rightShift(value, by: Scalar.Magnitude(Scalar.bitWidth / 2)) + CTAssertEqual(result, (high: (high: 0, low: upperHalf), low: (high: upperHalf, low: upperHalf))) + + value = ((Scalar(truncatingIfNeeded: lowerHalf), lowerHalf), (lowerHalf, lowerHalf)) + result = Complex.rightShift(value, by: 1) + CTAssertEqual(result, (high: (high: Scalar(truncatingIfNeeded: lowerHalf &>> 1), low: shiftedLowerHalf), low: (high: shiftedLowerHalf, low: shiftedLowerHalf))) + } + + private func testIsLessThanOrEqual(forType: Scalar.Type) where Scalar: FixedWidthInteger { + CTAssertTrue(Complex.isLessThanOrEqual(((1, 1), (1, 1)), to: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLessThanOrEqual(((0, 1), (1, 1)), to: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLessThanOrEqual(((1, 0), (1, 1)), to: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLessThanOrEqual(((1, 1), (0, 1)), to: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLessThanOrEqual(((1, 1), (1, 0)), to: ((1, 1), (1, 1)))) + CTAssertFalse(Complex.isLessThanOrEqual(((1, 1), (1, 1)), to: ((0, 1), (1, 1)))) + CTAssertFalse(Complex.isLessThanOrEqual(((1, 1), (1, 1)), to: ((1, 0), (1, 1)))) + CTAssertFalse(Complex.isLessThanOrEqual(((1, 1), (1, 1)), to: ((1, 1), (0, 1)))) + CTAssertFalse(Complex.isLessThanOrEqual(((1, 1), (1, 1)), to: ((1, 1), (1, 0)))) + + if Scalar.isSigned { + CTAssertTrue(Complex.isLessThanOrEqual(((~0, ~0), (~0, ~0)), to: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLessThanOrEqual(((~0 - 1, ~0), (~0, ~0)), to: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLessThanOrEqual(((~0, ~0 - 1), (~0, ~0)), to: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLessThanOrEqual(((~0, ~0), (~0 - 1, ~0)), to: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLessThanOrEqual(((~0, ~0), (~0, ~0 - 1)), to: ((~0, ~0), (~0, ~0)))) + CTAssertFalse(Complex.isLessThanOrEqual(((~0, ~0), (~0, ~0)), to: ((~0 - 1, ~0), (~0, ~0)))) + CTAssertFalse(Complex.isLessThanOrEqual(((~0, ~0), (~0, ~0)), to: ((~0, ~0 - 1), (~0, ~0)))) + CTAssertFalse(Complex.isLessThanOrEqual(((~0, ~0), (~0, ~0)), to: ((~0, ~0), (~0 - 1, ~0)))) + CTAssertFalse(Complex.isLessThanOrEqual(((~0, ~0), (~0, ~0)), to: ((~0, ~0), (~0, ~0 - 1)))) + } + } + + private func testIsLessThan(forType: Scalar.Type) where Scalar: FixedWidthInteger { + CTAssertFalse(Complex.isLess(((1, 1), (1, 1)), than: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLess(((0, 1), (1, 1)), than: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLess(((1, 0), (1, 1)), than: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLess(((1, 1), (0, 1)), than: ((1, 1), (1, 1)))) + CTAssertTrue(Complex.isLess(((1, 1), (1, 0)), than: ((1, 1), (1, 1)))) + CTAssertFalse(Complex.isLess(((1, 1), (1, 1)), than: ((0, 1), (1, 1)))) + CTAssertFalse(Complex.isLess(((1, 1), (1, 1)), than: ((1, 0), (1, 1)))) + CTAssertFalse(Complex.isLess(((1, 1), (1, 1)), than: ((1, 1), (0, 1)))) + CTAssertFalse(Complex.isLess(((1, 1), (1, 1)), than: ((1, 1), (1, 0)))) + + if Scalar.isSigned { + CTAssertFalse(Complex.isLess(((~0, ~0), (~0, ~0)), than: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLess(((~0 - 1, ~0), (~0, ~0)), than: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLess(((~0, ~0 - 1), (~0, ~0)), than: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLess(((~0, ~0), (~0 - 1, ~0)), than: ((~0, ~0), (~0, ~0)))) + CTAssertTrue(Complex.isLess(((~0, ~0), (~0, ~0 - 1)), than: ((~0, ~0), (~0, ~0)))) + CTAssertFalse(Complex.isLess(((~0, ~0), (~0, ~0)), than: ((~0 - 1, ~0), (~0, ~0)))) + CTAssertFalse(Complex.isLess(((~0, ~0), (~0, ~0)), than: ((~0, ~0 - 1), (~0, ~0)))) + CTAssertFalse(Complex.isLess(((~0, ~0), (~0, ~0)), than: ((~0, ~0), (~0 - 1, ~0)))) + CTAssertFalse(Complex.isLess(((~0, ~0), (~0, ~0)), than: ((~0, ~0), (~0, ~0 - 1)))) + } + } + + private func testIsPowerOfTwo(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var value: Complex.ExtendedScalar = ((0, 0), (0, 1)) + let extendedBitWidth = Scalar.bitWidth * 4 + + for i in 0 ..< extendedBitWidth { + let result = Complex.isPowerOfTwo(value) + value = Complex.leftShift(value, by: 1) + + CTAssertTrue(result.isPowerOfTwo) + CTAssertEqual(result.power, Scalar.Magnitude(i)) + } + + value = ((0, 0), (0, 2)) + + for _ in 1 ..< extendedBitWidth { + var testValue = value + testValue.low.low |= 1 + + let result = Complex.isPowerOfTwo(testValue) + value = Complex.leftShift(value, by: 1) + + CTAssertFalse(result.isPowerOfTwo) + CTAssertEqual(result.power, 0) + } + } + + private func testLeadingZeroBitCount(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var value: Complex.ExtendedScalar = ((~0, ~0), (~0, ~0)) + let extendedBitWidth = Scalar.bitWidth * 4 + + for i in 0 ..< extendedBitWidth { + CTAssertEqual(Complex.leadingZeroBitCount(of: value), i) + value = Complex.rightShift(value, by: 1) + } + + value = ((0, 0), (0, 1)) + + for i in 1 ..< extendedBitWidth { + CTAssertEqual(Complex.leadingZeroBitCount(of: value), extendedBitWidth - i) + value = Complex.leftShift(value, by: 1) + } + } + + private func testTruncateExtendedScalars(forType: Scalar.Type) where Scalar: FixedWidthInteger { + let randomValue: () -> Scalar.Magnitude = { .random(in: .min ... .max) } + + var result = Complex.truncateAndReportOverflow(((0, 0), (0, 0))) + CTAssertEqual(result.partialValue, 0) + CTAssertFalse(result.overflow) + + result = Complex.truncateAndReportOverflow(((0, 0), (0, Scalar.Magnitude(truncatingIfNeeded: Scalar.max)))) + CTAssertEqual(result.partialValue, Scalar.max) + CTAssertFalse(result.overflow) + + result = Complex.truncateAndReportOverflow(((0, 0), (0, Scalar.Magnitude(truncatingIfNeeded: Scalar.min)))) + CTAssertEqual(result.partialValue, Scalar.min) + CTAssertEqual(result.overflow, Scalar.isSigned) + + var value: Scalar.Magnitude + for _ in 0 ..< 64 { + value = randomValue() + result = Complex.truncateAndReportOverflow(((0, 0), (1, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + value = randomValue() + result = Complex.truncateAndReportOverflow(((0, 1), (0, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + value = randomValue() + result = Complex.truncateAndReportOverflow(((1, 0), (0, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + } + + if Scalar.isSigned { + value = randomValue() | (~Scalar.Magnitude.zero &<< (Scalar.bitWidth - 1)) // random value with the MSB set to 1 + result = Complex.truncateAndReportOverflow(((0, 0), (0, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + value = Scalar.Magnitude.max &>> 1 + result = Complex.truncateAndReportOverflow(((~0, ~0), (~0, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + value = randomValue() + result = Complex.truncateAndReportOverflow(((~0, ~0), (~0 - 1, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + value = randomValue() + result = Complex.truncateAndReportOverflow(((~0, ~0 - 1), (~0, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + value = randomValue() + result = Complex.truncateAndReportOverflow(((~0 - 1, ~0), (~0, value))) + CTAssertEqual(result.partialValue, Scalar(truncatingIfNeeded: value)) + CTAssertTrue(result.overflow) + + result = Complex.truncateAndReportOverflow(((~0, ~0), (~0, 1 << (Scalar.bitWidth - 1)))) + CTAssertEqual(result.partialValue, Scalar.min) + CTAssertFalse(result.overflow) + } + } + + private func testSlowpathMultiply(forType: Scalar.Type) where Scalar: FixedWidthInteger { + let value: Complex.ExtendedScalar = ((1, 1), (1, 1)) + let two: Complex.ExtendedScalar = ((0, 0), (0, 2)) + + var result = Complex.slowpathMultiply(two, value) + CTAssertEqual(result, Complex.leftShift(value, by: 1)) + + result = Complex.slowpathMultiply(value, two) + CTAssertEqual(result, Complex.leftShift(value, by: 1)) + + result = Complex.slowpathMultiply(Scalar(2), value) + CTAssertEqual(result, Complex.leftShift(value, by: 1)) + + result = Complex.slowpathMultiply(Scalar(0), value) + CTAssertEqual(result, ((0, 0), (0, 0))) + + result = Complex.slowpathMultiply(((0, 0), (0, 0)), value) + CTAssertEqual(result, ((0, 0), (0, 0))) + + result = Complex.slowpathMultiply(Scalar(1), value) + CTAssertEqual(result, value) + + result = Complex.slowpathMultiply(((0, 0), (0, 1)), value) + CTAssertEqual(result, value) + + result = Complex.slowpathMultiply(value, ((0, 0), (0, 1))) + CTAssertEqual(result, value) + + result = Complex.slowpathMultiply(value, ((0, 0), (0, ~0))) + CTAssertEqual(result, ((~0, ~0), (~0, ~0))) + + result = Complex.slowpathMultiply(((0, 0), (0, ~0)), value) + CTAssertEqual(result, ((~0, ~0), (~0, ~0))) + + if Scalar.isSigned { + result = Complex.slowpathMultiply(Scalar(-2), value) + CTAssertEqual(result, Complex.twosComplement(of: Complex.leftShift(value, by: 1))) + + result = Complex.slowpathMultiply(Complex.twosComplement(of: two), value) + CTAssertEqual(result, Complex.twosComplement(of: Complex.leftShift(value, by: 1))) + + result = Complex.slowpathMultiply(value, Complex.twosComplement(of: two)) + CTAssertEqual(result, Complex.twosComplement(of: Complex.leftShift(value, by: 1))) + + result = Complex.slowpathMultiply(Scalar(-1), value) + CTAssertEqual(result, Complex.twosComplement(of: value)) + + result = Complex.slowpathMultiply(((~0, ~0), (~0, ~0)), value) + CTAssertEqual(result, Complex.twosComplement(of: value)) + + result = Complex.slowpathMultiply(value, ((~0, ~0), (~0, ~0))) + CTAssertEqual(result, Complex.twosComplement(of: value)) + + result = Complex.slowpathMultiply(Scalar(-1), Complex.twosComplement(of: value)) + CTAssertEqual(result, value) + + result = Complex.slowpathMultiply(((~0, ~0), (~0, ~0)), Complex.twosComplement(of: value)) + CTAssertEqual(result, value) + + result = Complex.slowpathMultiply(Complex.twosComplement(of: value), ((~0, ~0), (~0, ~0))) + CTAssertEqual(result, value) + } + } + + private func testSlowpathDivide(forType: Scalar.Type) where Scalar: FixedWidthInteger { + var result = Complex.slowpathDivide(((0, 0), (0, 100)), ((0, 0), (0, 10))) // 100 / 10 = 10 r0 + CTAssertEqual(result.quotient, ((0, 0), (0, 10))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(((0, 0), (0, 101)), ((0, 0), (0, 10))) // 101 / 10 = 10 r1 + CTAssertEqual(result.quotient, ((0, 0), (0, 10))) + CTAssertEqual(result.remainder, ((0, 0), (0, 1))) + + result = Complex.slowpathDivide(((0, 0), (0, 109)), ((0, 0), (0, 10))) // 109 / 10 = 10 r9 + CTAssertEqual(result.quotient, ((0, 0), (0, 10))) + CTAssertEqual(result.remainder, ((0, 0), (0, 9))) + + result = Complex.slowpathDivide(((0, 0), (0, 100)), ((0, 0), (0, 2))) // 100 / 2 = 50 r0 + CTAssertEqual(result.quotient, ((0, 0), (0, 50))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(((0, 0), (0, 101)), ((0, 0), (0, 2))) // 101 / 2 = 50 r1 + CTAssertEqual(result.quotient, ((0, 0), (0, 50))) + CTAssertEqual(result.remainder, ((0, 0), (0, 1))) + + result = Complex.slowpathDivide(((0, 0), (0, 109)), ((0, 0), (0, 2))) // 101 / 2 = 54 r1 + CTAssertEqual(result.quotient, ((0, 0), (0, 54))) + CTAssertEqual(result.remainder, ((0, 0), (0, 1))) + + result = Complex.slowpathDivide(((0, 0), (0, 109)), ((0, 0), (0, 2))) // 101 / 2 = 54 r1 + CTAssertEqual(result.quotient, ((0, 0), (0, 54))) + CTAssertEqual(result.remainder, ((0, 0), (0, 1))) + + result = Complex.slowpathDivide(((0, ~0), (~0, ~0)), ((0, 0), (0, ~0))) + CTAssertEqual(result.quotient, ((0, 1), (1, 1))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(((0, 0), (0, ~0)), ((0, 0), (~0, ~0))) + CTAssertEqual(result.quotient, ((0, 0), (0, 0))) + CTAssertEqual(result.remainder, ((0, 0), (0, ~0))) + + if Scalar.isSigned { + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 100))), ((0, 0), (0, 10))) // -100 / 10 = -10 r0 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 10)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 100))), Complex.twosComplement(of: ((0, 0), (0, 10)))) // -100 / -10 = 10 r0 + CTAssertEqual(result.quotient, ((0, 0), (0, 10))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(((0, 0), (0, 100)), Complex.twosComplement(of: ((0, 0), (0, 10)))) // 100 / -10 = -10 r0 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 10)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + // + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 101))), ((0, 0), (0, 10))) // -101 / 10 = -10 r-1 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 10)))) + CTAssertEqual(result.remainder, ((~0, ~0), (~0, ~0))) + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 101))), Complex.twosComplement(of: ((0, 0), (0, 10)))) // -101 / -10 = 10 r-1 + CTAssertEqual(result.quotient, ((0, 0), (0, 10))) + CTAssertEqual(result.remainder, ((~0, ~0), (~0, ~0))) + + result = Complex.slowpathDivide(((0, 0), (0, 101)), Complex.twosComplement(of: ((0, 0), (0, 10)))) // 101 / -10 = -10 r1 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 10)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 1))) + + // + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 109))), ((0, 0), (0, 10))) // -109 / 10 = -10 r-9 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 10)))) + CTAssertEqual(result.remainder, Complex.twosComplement(of: ((0, 0), (0, 9)))) + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 109))), Complex.twosComplement(of: ((0, 0), (0, 10)))) // -109 / -10 = 10 r-9 + CTAssertEqual(result.quotient, ((0, 0), (0, 10))) + CTAssertEqual(result.remainder, Complex.twosComplement(of: ((0, 0), (0, 9)))) + + result = Complex.slowpathDivide(((0, 0), (0, 109)), Complex.twosComplement(of: ((0, 0), (0, 10)))) // 109 / -10 = -10 r9 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 10)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 9))) + + // + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 100))), ((0, 0), (0, 2))) // -100 / 2 = -50 r0 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 50)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(((0, 0), (0, 100)), ((0, 0), (0, 2))) // -100 / -2 = 50 r0 + CTAssertEqual(result.quotient, ((0, 0), (0, 50))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + result = Complex.slowpathDivide(((0, 0), (0, 100)), Complex.twosComplement(of: ((0, 0), (0, 2)))) // 100 / -2 = -50 r0 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 50)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 0))) + + // + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 101))), ((0, 0), (0, 2))) // -101 / 2 = -50 r-1 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 50)))) + CTAssertEqual(result.remainder, ((~0, ~0), (~0, ~0))) + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, 101))), Complex.twosComplement(of: ((0, 0), (0, 2)))) // -101 / -2 = 50 r-1 + CTAssertEqual(result.quotient, ((0, 0), (0, 50))) + CTAssertEqual(result.remainder, ((~0, ~0), (~0, ~0))) + + result = Complex.slowpathDivide(((0, 0), (0, 101)), Complex.twosComplement(of: ((0, 0), (0, 2)))) // 101 / -2 = -50 r1 + CTAssertEqual(result.quotient, Complex.twosComplement(of: ((0, 0), (0, 50)))) + CTAssertEqual(result.remainder, ((0, 0), (0, 1))) + + // + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, ~0))), ((0, 0), (~0, ~0))) + CTAssertEqual(result.quotient, ((0, 0), (0, 0))) + CTAssertEqual(result.remainder, Complex.twosComplement(of: ((0, 0), (0, ~0)))) + + result = Complex.slowpathDivide(Complex.twosComplement(of: ((0, 0), (0, ~0))), Complex.twosComplement(of: ((0, 0), (~0, ~0)))) + CTAssertEqual(result.quotient, ((0, 0), (0, 0))) + CTAssertEqual(result.remainder, Complex.twosComplement(of: ((0, 0), (0, ~0)))) + + result = Complex.slowpathDivide(((0, 0), (0, ~0)), Complex.twosComplement(of: ((0, 0), (~0, ~0)))) + CTAssertEqual(result.quotient, ((0, 0), (0, 0))) + CTAssertEqual(result.remainder, ((0, 0), (0, ~0))) + } + } } diff --git a/Tests/ComplexTests/TestingBase.swift b/Tests/ComplexTests/TestingBase.swift index 5c6b5d4..7bc8032 100644 --- a/Tests/ComplexTests/TestingBase.swift +++ b/Tests/ComplexTests/TestingBase.swift @@ -11,7 +11,7 @@ import XCTest // MARK: Internal Methods internal func CTAssertEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) where T: Equatable { - XCTAssertEqual(try expression1(), try expression2(), "\(testMethodDescription(forType: T.self, function: function))\(message().isEmpty ? "" : ": \(message())")", file: file, line: line) + CTAssertEqual(try expression1(), try expression2(), message(), function: function, type: T.self, file: file, line: line) } internal func CTAssertTrue(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) { @@ -27,8 +27,24 @@ internal func CTAssertEqual(_ expression1: @autoclosure () throws -> Complex< CTAssertTrue(difference.real <= accuracy && difference.imaginary <= accuracy, message(), function: function, file: file, line: line) } +internal func CTAssertEqual(_ expression1: @autoclosure () -> Complex.ExtendedScalar, _ expression2: @autoclosure () -> Complex.ExtendedScalar, _ message: @autoclosure () -> String = "", function: String = #function, file: StaticString = #file, line: UInt = #line) where Scalar: FixedWidthInteger { + let lhs = expression1() + let rhs = expression2() + + CTAssertEqual(lhs.high.high, rhs.high.high, "ExtendedScalar<\(String(describing: Scalar.self))>.high.high\(message().isEmpty ? "" : ": \(message())")", function: function, type: Scalar.self, file: file, line: line) + CTAssertEqual(lhs.high.low, rhs.high.low, "ExtendedScalar<\(String(describing: Scalar.self))>.high.low\(message().isEmpty ? "" : ": \(message())")", function: function, type: Scalar.self, file: file, line: line) + CTAssertEqual(lhs.low.high, rhs.low.high, "ExtendedScalar<\(String(describing: Scalar.self))>.low.high\(message().isEmpty ? "" : ": \(message())")", function: function, type: Scalar.self, file: file, line: line) + CTAssertEqual(lhs.low.low, rhs.low.low, "ExtendedScalar<\(String(describing: Scalar.self))>.low.low\(message().isEmpty ? "" : ": \(message())")", function: function, type: Scalar.self, file: file, line: line) +} + // MARK: - Private Methods +//swiftlint:disable function_default_parameter_at_end +private func CTAssertEqual(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", function: String = #function, type: Scalar.Type, file: StaticString = #file, line: UInt = #line) where T: Equatable { + XCTAssertEqual(try expression1(), try expression2(), "\(testMethodDescription(forType: Scalar.self, function: function))\(message().isEmpty ? "" : ": \(message())")", file: file, line: line) +} +//swiftlint:enable function_default_parameter_at_end + private func testMethodDescription(forType type: Scalar.Type, function: String = #function) -> String { let description: String if let index = function.firstIndex(of: "(") { From 9edf42b97ab0cc69c68fb2d9b44df1b32b55cb65 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Mon, 24 Feb 2020 07:15:58 -0500 Subject: [PATCH 12/13] Updated README with Swift Package Github Action badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0dd8f3e..e408139 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Complex [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Platform](https://img.shields.io/cocoapods/p/Complex.svg)](https://cocoapods.org/pods/Complex) [![Build](https://travis-ci.com/SomeRandomiOSDev/Complex.svg?branch=master)](https://travis-ci.com/SomeRandomiOSDev/Complex) +![Swift](https://github.com/SomeRandomiOSDev/Complex/workflows/Swift/badge.svg) [![Code Coverage](https://codecov.io/gh/SomeRandomiOSDev/Complex/branch/master/graph/badge.svg)](https://codecov.io/gh/SomeRandomiOSDev/Complex) [![Codacy](https://api.codacy.com/project/badge/Grade/8ad52c117e4a46d9aa4699d22fc0bf49)](https://app.codacy.com/app/SomeRandomiOSDev/Complex?utm_source=github.com&utm_medium=referral&utm_content=SomeRandomiOSDev/Complex&utm_campaign=Badge_Grade_Dashboard) From 8890b7f02b39b75080b7556e0a5116928579ec13 Mon Sep 17 00:00:00 2001 From: Joe Newton <> Date: Mon, 24 Feb 2020 07:39:53 -0500 Subject: [PATCH 13/13] Updated podspec version --- Complex.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Complex.podspec b/Complex.podspec index c39379d..7924dae 100644 --- a/Complex.podspec +++ b/Complex.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = "Complex" - s.version = "1.0.0" + s.version = "1.1.0" s.summary = "Swift Complex Number" s.description = <<-DESC A lightweight framework designed for representing and working with complex numbers for iOS, macOS, tvOS, and watchOS.