Skip to content

Commit 81acc87

Browse files
committed
Add more trig functions for vector
1 parent 97fc18d commit 81acc87

3 files changed

Lines changed: 165 additions & 5 deletions

File tree

Sources/VectorModule/Documentation.docc/Trigonometry.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ Trigonometic vector operations.
44

55
## Overview
66

7-
Numerix provides several element-wise trigometric functions for vectors. The Accelerate framework is utilized for efficient element-by-element vector operations.
7+
Numerix provides several element-wise trigonometic functions for vectors. The Accelerate framework is utilized for efficient element-by-element vector operations.
88

99
## Topics
1010

1111
- ``sin(_:)``
1212
- ``cos(_:)``
1313
- ``tan(_:)``
14+
- ``asin(_:)``
15+
- ``acos(_:)``
16+
- ``atan(_:)``
17+
- ``csc(_:)``
18+
- ``sec(_:)``
19+
- ``cot(_:)``

Sources/VectorModule/Trigonometry.swift

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ public protocol Trigonometry {
99
static func sin(_ a: Vector<Self>) -> Vector<Self>
1010
static func cos(_ a: Vector<Self>) -> Vector<Self>
1111
static func tan(_ a: Vector<Self>) -> Vector<Self>
12+
static func asin(_ a: Vector<Self>) -> Vector<Self>
13+
static func acos(_ a: Vector<Self>) -> Vector<Self>
14+
static func atan(_ a: Vector<Self>) -> Vector<Self>
15+
static func csc(_ a: Vector<Self>) -> Vector<Self>
16+
static func sec(_ a: Vector<Self>) -> Vector<Self>
17+
static func cot(_ a: Vector<Self>) -> Vector<Self>
1218
}
1319

1420
@_documentation(visibility: private)
@@ -31,6 +37,45 @@ extension Float: Trigonometry {
3137
vForce.tan(a.buffer, result: &result.buffer)
3238
return result
3339
}
40+
41+
public static func asin(_ a: Vector<Float>) -> Vector<Float> {
42+
var result = Vector(like: a)
43+
vForce.asin(a.buffer, result: &result.buffer)
44+
return result
45+
}
46+
47+
public static func acos(_ a: Vector<Float>) -> Vector<Float> {
48+
var result = Vector(like: a)
49+
vForce.acos(a.buffer, result: &result.buffer)
50+
return result
51+
}
52+
53+
public static func atan(_ a: Vector<Float>) -> Vector<Float> {
54+
var result = Vector(like: a)
55+
vForce.atan(a.buffer, result: &result.buffer)
56+
return result
57+
}
58+
59+
public static func csc(_ a: Vector<Float>) -> Vector<Float> {
60+
var result = Vector(like: a)
61+
vForce.sin(a.buffer, result: &result.buffer)
62+
vForce.reciprocal(result.buffer, result: &result.buffer)
63+
return result
64+
}
65+
66+
public static func sec(_ a: Vector<Float>) -> Vector<Float> {
67+
var result = Vector(like: a)
68+
vForce.cos(a.buffer, result: &result.buffer)
69+
vForce.reciprocal(result.buffer, result: &result.buffer)
70+
return result
71+
}
72+
73+
public static func cot(_ a: Vector<Float>) -> Vector<Float> {
74+
var result = Vector(like: a)
75+
vForce.tan(a.buffer, result: &result.buffer)
76+
vForce.reciprocal(result.buffer, result: &result.buffer)
77+
return result
78+
}
3479
}
3580

3681
@_documentation(visibility: private)
@@ -53,6 +98,45 @@ extension Double: Trigonometry {
5398
vForce.tan(a.buffer, result: &result.buffer)
5499
return result
55100
}
101+
102+
public static func asin(_ a: Vector<Double>) -> Vector<Double> {
103+
var result = Vector(like: a)
104+
vForce.asin(a.buffer, result: &result.buffer)
105+
return result
106+
}
107+
108+
public static func acos(_ a: Vector<Double>) -> Vector<Double> {
109+
var result = Vector(like: a)
110+
vForce.acos(a.buffer, result: &result.buffer)
111+
return result
112+
}
113+
114+
public static func atan(_ a: Vector<Double>) -> Vector<Double> {
115+
var result = Vector(like: a)
116+
vForce.atan(a.buffer, result: &result.buffer)
117+
return result
118+
}
119+
120+
public static func csc(_ a: Vector<Double>) -> Vector<Double> {
121+
var result = Vector(like: a)
122+
vForce.sin(a.buffer, result: &result.buffer)
123+
vForce.reciprocal(result.buffer, result: &result.buffer)
124+
return result
125+
}
126+
127+
public static func sec(_ a: Vector<Double>) -> Vector<Double> {
128+
var result = Vector(like: a)
129+
vForce.cos(a.buffer, result: &result.buffer)
130+
vForce.reciprocal(result.buffer, result: &result.buffer)
131+
return result
132+
}
133+
134+
public static func cot(_ a: Vector<Double>) -> Vector<Double> {
135+
var result = Vector(like: a)
136+
vForce.tan(a.buffer, result: &result.buffer)
137+
vForce.reciprocal(result.buffer, result: &result.buffer)
138+
return result
139+
}
56140
}
57141

58142
/// Calculate the sine of each element in a vector.
@@ -87,3 +171,51 @@ public func cos<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: T
87171
public func tan<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
88172
Scalar.tan(vec)
89173
}
174+
175+
/// Calculate the arcsine of each element in a vector.
176+
///
177+
/// Elements in the vector should be within the domain -1 ≤ x ≤ 1 otherwise results may be nan. Results are returned on the closed interval -π / 2 ≤ y ≤ π / 2.
178+
/// ```swift
179+
/// let vec = Vector([-1, -0.5, 0, 0.5, 1])
180+
/// let result = asin(vec)
181+
/// ```
182+
/// - Parameter vec: The input vector with values from -1 to 1.
183+
/// - Returns: A vector representing the arcsine of the input vector.
184+
public func asin<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
185+
Scalar.asin(vec)
186+
}
187+
188+
/// Calculate the arccosine of each element in a vector.
189+
/// - Parameter vec: The input vector.
190+
/// - Returns: A vector representing the arccosine of the input vector.
191+
public func acos<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
192+
Scalar.acos(vec)
193+
}
194+
195+
/// Calculate the arctangent of each element in a vector.
196+
/// - Parameter vec: The input vector.
197+
/// - Returns: A vector representing the arctangent of the input vector.
198+
public func atan<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
199+
Scalar.atan(vec)
200+
}
201+
202+
/// Calculate the cosecant as 1 / sinθ for each element in a vector.
203+
/// - Parameter vec: The input vector.
204+
/// - Returns: A vector representing the cosecant of the input vector.
205+
public func csc<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
206+
Scalar.csc(vec)
207+
}
208+
209+
/// Calculate the secant as 1 / cosθ for each element in a vector.
210+
/// - Parameter vec: The input vector.
211+
/// - Returns: A vector representing the secant of the input vector.
212+
public func sec<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
213+
Scalar.sec(vec)
214+
}
215+
216+
/// Calculate the cotangent as 1 / tanθ for each element in a vector.
217+
/// - Parameter vec: The input vector.
218+
/// - Returns: A vector representing the cotangent of the input vector.
219+
public func cot<Scalar>(_ vec: Vector<Scalar>) -> Vector<Scalar> where Scalar: Trigonometry {
220+
Scalar.cot(vec)
221+
}

Tests/TrigonometryTests.swift

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,41 @@ import Testing
77

88
struct TrigonometryTests {
99

10-
@Test func vectorTrigonometry() {
11-
let a = Vector<Float>([1, 2, 3, 4])
10+
@Test func vectorTrig() {
11+
let a = Vector<Float>([1, 2, 3, 4]) // single precision
12+
1213
#expect(sin(a).isApproximatelyEqual(to: [0.841471, 0.909297, 0.14112, -0.756802]))
1314
#expect(cos(a).isApproximatelyEqual(to: [0.540302, -0.416147, -0.989992, -0.653644]))
1415
#expect(tan(a).isApproximatelyEqual(to: [1.55741, -2.18504, -0.142547, 1.15782], relativeTolerance: 1e-4))
16+
17+
#expect(csc(a).isApproximatelyEqual(to: [1.18839511, 1.09975017, 7.0861674, -1.32134871]))
18+
#expect(sec(a).isApproximatelyEqual(to: [1.85081572, -2.40299796, -1.01010867, -1.52988566]))
19+
#expect(cot(a).isApproximatelyEqual(to: [0.64209262, -0.45765755, -7.01525255, 0.86369115]))
1520

16-
let b = Vector([1, 2, 3, 4.0])
21+
let b = Vector([1, 2, 3, 4.0]) // double precision
22+
1723
#expect(sin(b).isApproximatelyEqual(to: [0.841471, 0.909297, 0.14112, -0.756802], relativeTolerance: 1e-4))
1824
#expect(cos(b).isApproximatelyEqual(to: [0.540302, -0.416147, -0.989992, -0.6536], relativeTolerance: 1e-4))
1925
#expect(tan(b).isApproximatelyEqual(to: [1.55741, -2.18504, -0.142547, 1.15782], relativeTolerance: 1e-4))
26+
27+
#expect(csc(b).isApproximatelyEqual(to: [1.18839511, 1.09975017, 7.0861674, -1.32134871]))
28+
#expect(sec(b).isApproximatelyEqual(to: [1.85081572, -2.40299796, -1.01010867, -1.52988566]))
29+
#expect(cot(b).isApproximatelyEqual(to: [0.64209262, -0.45765755, -7.01525255, 0.86369115]))
2030
}
31+
32+
@Test func vectorArcTrig() {
33+
let a = Vector<Float>([-1, -0.5, 0, 0.5, 1]) // single precision
34+
#expect(asin(a) == [-1.57079633, -0.52359878, 0.0, 0.52359878, 1.57079633])
35+
#expect(acos(a) == [3.14159265, 2.0943951, 1.57079633, 1.04719755, 0.0])
36+
#expect(atan(a) == [-0.78539816, -0.46364761, 0.0, 0.46364761, 0.78539816])
2137

22-
@Test func matrixTrigonometry() {
38+
let b = Vector([-1, -0.5, 0, 0.5, 1]) // double precision
39+
#expect(asin(b).isApproximatelyEqual(to: [-1.57079633, -0.52359878, 0.0, 0.52359878, 1.57079633]))
40+
#expect(acos(b).isApproximatelyEqual(to: [3.14159265, 2.0943951, 1.57079633, 1.04719755, 0.0]))
41+
#expect(atan(b).isApproximatelyEqual(to: [-0.78539816, -0.46364761, 0.0, 0.46364761, 0.78539816]))
42+
}
43+
44+
@Test func matrixTrig() {
2345
let a = Matrix<Float>([[1, 2], [3, 4]])
2446
#expect(sin(a).isApproximatelyEqual(to: [[0.841471, 0.909297], [0.14112, -0.756802]]))
2547
#expect(cos(a).isApproximatelyEqual(to: [[0.540302, -0.416147], [-0.989992, -0.653644]]))

0 commit comments

Comments
 (0)