Skip to content

Commit 669d011

Browse files
committed
Account for over and underflow in quaternion length
1 parent 5ac7546 commit 669d011

File tree

2 files changed

+17
-1
lines changed

2 files changed

+17
-1
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)`.

Tests/QuaternionTests/PropertyTests.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ 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)
3742
}
3843

3944
func testProperties() {

0 commit comments

Comments
 (0)