Skip to content

Commit 6351289

Browse files
committed
Merge branch 'quaternions' into quaternion/elfns
2 parents 58fa7e7 + 65cf88a commit 6351289

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

Sources/QuaternionModule/Norms.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,19 @@ extension Quaternion {
7777
/// - `.lengthSquared`
7878
@_transparent
7979
public var length: RealType {
80+
let naive = lengthSquared
81+
guard naive.isNormal else { return carefulLength }
82+
return .sqrt(naive)
83+
}
84+
85+
// Internal implementation detail of `length`, moving slow path off
86+
// of the inline function.
87+
@usableFromInline
88+
internal var carefulLength: RealType {
8089
guard isFinite else { return .infinity }
81-
return .sqrt(lengthSquared)
90+
guard !magnitude.isZero else { return .zero }
91+
// Unscale the quaternion, calculate its length and rescale the result
92+
return divided(by: magnitude).length * magnitude
8293
}
8394

8495
/// The squared length `(r*r + x*x + y*y + z*z)`.

Sources/QuaternionModule/Quaternion.swift

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ extension Quaternion {
186186
/// - `.isNormal`
187187
/// - `.isSubnormal`
188188
/// - `.isZero`
189+
/// - `.isReal`
189190
/// - `.isPure`
190191
@_transparent
191192
public var isFinite: Bool {
@@ -206,6 +207,7 @@ extension Quaternion {
206207
/// - `.isFinite`
207208
/// - `.isSubnormal`
208209
/// - `.isZero`
210+
/// - `.isReal`
209211
/// - `.isPure`
210212
@_transparent
211213
public var isNormal: Bool {
@@ -228,6 +230,7 @@ extension Quaternion {
228230
/// - `.isFinite`
229231
/// - `.isNormal`
230232
/// - `.isZero`
233+
/// - `.isReal`
231234
/// - `.isPure`
232235
@_transparent
233236
public var isSubnormal: Bool {
@@ -243,13 +246,40 @@ extension Quaternion {
243246
/// - `.isFinite`
244247
/// - `.isNormal`
245248
/// - `.isSubnormal`
249+
/// - `.isReal`
246250
/// - `.isPure`
247251
@_transparent
248252
public var isZero: Bool {
249253
components == .zero
250254
}
251255

252-
/// True if this value is only defined by the imaginary part (`real == .zero`)
256+
/// True if this quaternion is real.
257+
///
258+
/// A quaternion is real if *all* imaginary components are zero.
259+
///
260+
/// See also:
261+
/// -
262+
/// - `.isFinite`
263+
/// - `.isNormal`
264+
/// - `.isSubnormal`
265+
/// - `.isZero`
266+
/// - `.isPure`
267+
@_transparent
268+
public var isReal: Bool {
269+
imaginary == .zero
270+
}
271+
272+
/// True if this quaternion is pure.
273+
///
274+
/// A quaternion is pure if the real component is zero.
275+
///
276+
/// See also:
277+
/// -
278+
/// - `.isFinite`
279+
/// - `.isNormal`
280+
/// - `.isSubnormal`
281+
/// - `.isZero`
282+
/// - `.isReal`
253283
@_transparent
254284
public var isPure: Bool {
255285
real.isZero

Tests/QuaternionTests/PropertyTests.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ final class PropertyTests: XCTestCase {
3434
XCTAssertEqual(Quaternion<T>.zero.length, .zero)
3535
XCTAssertEqual(Quaternion<T>(real: .zero, imaginary: -.zero).length, .zero)
3636
XCTAssertEqual(Quaternion<T>(real: -.zero, imaginary: -.zero).length, .zero)
37+
// Check for overflow and underflow when calculating the length
38+
XCTAssertEqual(Quaternion<T>(real: .greatestFiniteMagnitude, imaginary: 0, 0, 0).length, .greatestFiniteMagnitude)
39+
XCTAssertEqual(Quaternion<T>(real: 0, imaginary: -.greatestFiniteMagnitude, 0, 0).length, .greatestFiniteMagnitude)
40+
XCTAssertEqual(Quaternion<T>(real: 0, imaginary: 0, .leastNormalMagnitude, 0).length, .leastNormalMagnitude)
41+
XCTAssertEqual(Quaternion<T>(real: 0, imaginary: 0, 0, -.leastNormalMagnitude).length, .leastNormalMagnitude)
42+
// The properties of pure and real
43+
XCTAssertTrue(Quaternion<T>.zero.isPure) // zero quaternion is both, pure...
44+
XCTAssertTrue(Quaternion<T>.zero.isReal) // and real
45+
XCTAssertFalse(Quaternion<T>(1).isPure)
46+
XCTAssertTrue(Quaternion<T>(1).isReal)
47+
XCTAssertTrue(Quaternion<T>(real: .zero, imaginary: 1, 0, 0).isPure)
48+
XCTAssertFalse(Quaternion<T>(real: .zero, imaginary: 1, 0, 0).isReal)
49+
XCTAssertFalse(Quaternion<T>(from: SIMD4(repeating: 1)).isPure)
50+
XCTAssertFalse(Quaternion<T>(from: SIMD4(repeating: 1)).isReal)
3751
}
3852

3953
func testProperties() {

0 commit comments

Comments
 (0)