Skip to content

Commit ae364a2

Browse files
Merge pull request #162 from apple/complex-elfns
Conform Complex to Elementary Functions
2 parents e042c13 + 1683729 commit ae364a2

File tree

13 files changed

+1312
-75
lines changed

13 files changed

+1312
-75
lines changed

Package.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,30 @@
1313
import PackageDescription
1414

1515
let package = Package(
16+
1617
name: "swift-numerics",
1718
products: [
1819
.library(name: "ComplexModule", targets: ["ComplexModule"]),
1920
.library(name: "Numerics", targets: ["Numerics"]),
2021
.library(name: "RealModule", targets: ["RealModule"]),
2122
],
22-
dependencies: [
23-
],
23+
2424
targets: [
25+
// User-facing modules
2526
.target(name: "ComplexModule", dependencies: ["RealModule"]),
2627
.target(name: "Numerics", dependencies: ["ComplexModule", "RealModule"]),
2728
.target(name: "RealModule", dependencies: ["_NumericsShims"]),
2829

30+
// Implementation details
2931
.target(name: "_NumericsShims", dependencies: []),
3032
.target(name: "_TestSupport", dependencies: ["Numerics"]),
3133

34+
// Unit test bundles
3235
.testTarget(name: "ComplexTests", dependencies: ["_TestSupport"]),
3336
.testTarget(name: "RealTests", dependencies: ["_TestSupport"]),
37+
38+
// Test executables
39+
.target(name: "ComplexLog", dependencies: ["Numerics", "_TestSupport"], path: "Tests/Executable/ComplexLog"),
40+
.target(name: "ComplexLog1p", dependencies: ["Numerics", "_TestSupport"], path: "Tests/Executable/ComplexLog1p")
3441
]
3542
)

Sources/ComplexModule/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ See https://swift.org/LICENSE.txt for license information
1010
add_library(ComplexModule
1111
Arithmetic.swift
1212
Complex.swift
13-
Differentiable.swift)
13+
Differentiable.swift
14+
ElementaryFunctions.swift)
1415
set_target_properties(ComplexModule PROPERTIES
1516
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})
1617
target_link_libraries(ComplexModule PUBLIC

Sources/ComplexModule/ElementaryFunctions.swift

Lines changed: 453 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===--- AugmentedArithmetic.swift ----------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift Numerics open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift Numerics project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
public enum Augmented { }
13+
14+
extension Augmented {
15+
@_transparent
16+
public static func twoProdFMA<T:Real>(_ a: T, _ b: T) -> (head: T, tail: T) {
17+
let head = a*b
18+
let tail = (-head).addingProduct(a, b)
19+
return (head, tail)
20+
}
21+
22+
@_transparent
23+
public static func fastTwoSum<T:Real>(_ a: T, _ b: T) -> (head: T, tail: T) {
24+
assert(!(b.magnitude > a.magnitude))
25+
let head = a + b
26+
let tail = a - head + b
27+
return (head, tail)
28+
}
29+
}

Sources/_NumericsShims/include/_NumericsShims.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,4 +417,10 @@ HEADER_SHIM CComplex libm_cmul(CComplex z, CComplex w) {
417417
double _Complex c = a*b;
418418
return (CComplex){ __real__ c, __imag__ c };
419419
}
420+
421+
HEADER_SHIM CComplex libm_catanh(CComplex z) {
422+
double _Complex a = { z.real, z.imag };
423+
double _Complex w = __builtin_catanh(a);
424+
return (CComplex){ __real__ w, __imag__ w };
425+
}
420426
#endif // !defined _WIN32

Sources/_TestSupport/Error.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===--- Error.swift ------------------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import ComplexModule
14+
15+
public func relativeError(_ tst: Float, _ ref: Double) -> Double {
16+
let scale = max(ref.magnitude, Double(Float.leastNormalMagnitude))
17+
let error = (Double(tst) - ref).magnitude
18+
return error / scale
19+
}
20+
21+
public func componentwiseError(_ tst: Complex<Float>, _ ref: Complex<Double>) -> Double {
22+
return max(relativeError(tst.real, ref.real),
23+
relativeError(tst.imaginary, ref.imaginary))
24+
}
25+
26+
public func relativeError(_ tst: Complex<Float>, _ ref: Complex<Double>) -> Double {
27+
let scale = max(ref.magnitude, Double(Float.leastNormalMagnitude))
28+
let dtst = Complex(Double(tst.real), Double(tst.imaginary))
29+
let error = (dtst - ref).magnitude
30+
return error / scale
31+
}

Sources/_TestSupport/Interval.swift

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- Interval.swift ---------------------------------------*- swift -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// A not-particularly-clever floating-point iterval that is iterable for the
14+
// purposes of testing.
15+
public struct Interval<Element>: Sequence where Element: FloatingPoint {
16+
17+
let lower: Element
18+
19+
let upper: Element
20+
21+
public init(from: Element, through: Element) {
22+
precondition(from <= through)
23+
lower = from
24+
upper = through
25+
}
26+
27+
public init(from: Element, to: Element) {
28+
self.init(from: from, through: to.nextDown)
29+
}
30+
31+
public func makeIterator() -> Iterator {
32+
Iterator(self)
33+
}
34+
35+
public struct Iterator: IteratorProtocol {
36+
let interval: Interval
37+
var nextOutput: Element?
38+
39+
init(_ interval: Interval) {
40+
self.interval = interval
41+
self.nextOutput = interval.lower
42+
}
43+
44+
public mutating func next() -> Element? {
45+
let result = nextOutput
46+
if nextOutput == interval.upper { nextOutput = nil }
47+
else { nextOutput = nextOutput?.nextUp }
48+
return result
49+
}
50+
}
51+
}

Sources/_TestSupport/RealTestSupport.swift

Lines changed: 1 addition & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,86 +2,15 @@
22
//
33
// This source file is part of the Swift Numerics open source project
44
//
5-
// Copyright (c) 2019 Apple Inc. and the Swift Numerics project authors
5+
// Copyright (c) 2019-2020 Apple Inc. and the Swift Numerics project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
import XCTest
1312
import RealModule
1413

15-
#if (arch(i386) || arch(x86_64)) && !os(Windows) && !os(Android)
16-
public typealias TestLiteralType = Float80
17-
#else
18-
public typealias TestLiteralType = Double
19-
#endif
20-
21-
@discardableResult
22-
public func assertClose<T>(
23-
_ expected: TestLiteralType,
24-
_ observed: T,
25-
allowedError: T = 16,
26-
file: StaticString = #file,
27-
line: UInt = #line
28-
) -> T where T: BinaryFloatingPoint {
29-
// Shortcut relative-error check if we got the sign wrong; it's OK to
30-
// underflow to zero, but we do not want to allow going right through
31-
// zero and getting the sign wrong.
32-
guard observed.sign == expected.sign else {
33-
print("Sign was wrong: expected \(expected) but saw \(observed).")
34-
XCTFail(file: file, line: line)
35-
return .infinity
36-
}
37-
if observed.isNaN && expected.isNaN { return 0 }
38-
// If T(expected) is zero or infinite, and matches observed, the error
39-
// is zero.
40-
let expectedT = T(expected)
41-
if observed.isZero && expectedT.isZero { return 0 }
42-
if observed.isInfinite && expectedT.isInfinite { return 0 }
43-
// Special-case where only one of expectedT or observed is infinity.
44-
// Artificially knock everything down a binade, treat actual infinity as
45-
// the base of the next binade up.
46-
func topBinade(signOf x: T) -> T {
47-
T(signOf: x, magnitudeOf: T.greatestFiniteMagnitude.binade)
48-
}
49-
if observed.isInfinite {
50-
return assertClose(
51-
expected/2, topBinade(signOf: observed),
52-
allowedError: allowedError, file: file, line: line
53-
)
54-
}
55-
if expectedT.isInfinite {
56-
return assertClose(
57-
TestLiteralType(topBinade(signOf: expectedT)), observed/2,
58-
allowedError: allowedError, file: file, line: line
59-
)
60-
}
61-
// Compute error in ulp, compare to tolerance.
62-
let absoluteError = (TestLiteralType(observed) - expected).magnitude
63-
let scale = max(expectedT.magnitude, T.leastNormalMagnitude).ulp
64-
let ulps = T(absoluteError/TestLiteralType(scale))
65-
if ulps > allowedError {
66-
print("ULP error was unacceptably large: expected \(expected) but saw \(observed) (\(ulps)-ulp error).")
67-
XCTFail(file: file, line: line)
68-
}
69-
return ulps
70-
}
71-
72-
public func assertClose<T>(
73-
_ expected: TestLiteralType,
74-
_ observed: T,
75-
allowedError: T = 16,
76-
worstError: inout T,
77-
file: StaticString = #file,
78-
line: UInt = #line
79-
) where T: BinaryFloatingPoint {
80-
worstError = max(worstError, assertClose(
81-
expected, observed, allowedError: allowedError, file: file, line: line
82-
))
83-
}
84-
8514
public protocol FixedWidthFloatingPoint: BinaryFloatingPoint
8615
where Exponent: FixedWidthInteger,
8716
RawSignificand: FixedWidthInteger { }

Tests/ComplexTests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_library(ComplexTests
1111
ApproximateEqualityTests.swift
1212
ArithmeticTests.swift
1313
DifferentiableTests.swift
14+
ElementaryFunctionTests.swift
1415
PropertyTests.swift)
1516
set_target_properties(ComplexTests PROPERTIES
1617
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_Swift_MODULE_DIRECTORY})

0 commit comments

Comments
 (0)