From f6c2c34910a2f013283e601858a74cf4466d7b36 Mon Sep 17 00:00:00 2001 From: Stephen Canon Date: Wed, 20 Nov 2019 16:15:10 -0500 Subject: [PATCH] Rename unsafeLengthSquared -> lengthSquared MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also further tweak polar init for Complex to allow (-infinity, θ) when θ is not finite. --- Sources/Complex/Arithmetic.swift | 8 ++++---- Sources/Complex/Complex.swift | 23 +++++++++++++---------- Tests/ComplexTests/ArithmeticTests.swift | 21 ++++++++++++--------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Sources/Complex/Arithmetic.swift b/Sources/Complex/Arithmetic.swift index 5a15f8c8..2c003072 100644 --- a/Sources/Complex/Arithmetic.swift +++ b/Sources/Complex/Arithmetic.swift @@ -73,9 +73,9 @@ extension Complex: Numeric { // Try the naive expression z/w = z*conj(w) / |w|^2; if we can compute // this without over/underflow, everything is fine and the result is // correct. If not, we have to rescale and do the computation carefully. - let lengthSquared = w.unsafeLengthSquared - guard lengthSquared.isNormal else { return rescaledDivide(z, w) } - return z * (w.conjugate.divided(by: lengthSquared)) + let lenSq = w.lengthSquared + guard lenSq.isNormal else { return rescaledDivide(z, w) } + return z * (w.conjugate.divided(by: lenSq)) } @_transparent @@ -98,7 +98,7 @@ extension Complex: Numeric { let wScale = w.magnitude let zNorm = z.divided(by: zScale) let wNorm = w.divided(by: wScale) - let r = (zNorm * wNorm.conjugate).divided(by: wNorm.unsafeLengthSquared) + let r = (zNorm * wNorm.conjugate).divided(by: wNorm.lengthSquared) // At this point, the result is (r * zScale)/wScale computed without // undue overflow or underflow. We know that r is close to unity, so // the question is simply what order in which to do this computation diff --git a/Sources/Complex/Complex.swift b/Sources/Complex/Complex.swift index fc394077..6d7b327d 100644 --- a/Sources/Complex/Complex.swift +++ b/Sources/Complex/Complex.swift @@ -208,7 +208,7 @@ extension Complex { /// The ∞-norm of the value (`max(abs(real), abs(imaginary))`). /// - /// If you need the euclidean norm (a.k.a. 2-norm) use the `length` or `unsafeLengthSquared` + /// If you need the euclidean norm (a.k.a. 2-norm) use the `length` or `lengthSquared` /// properties instead. /// /// Edge cases: @@ -220,7 +220,7 @@ extension Complex { /// See also: /// - /// - `.length` - /// - `.unsafeLengthSquared` + /// - `.lengthSquared` @_transparent public var magnitude: RealType { guard isFinite else { return .infinity } @@ -394,13 +394,13 @@ extension Complex { /// See also: /// - /// - `.magnitude` - /// - `.unsafeLengthSquared` + /// - `.lengthSquared` /// - `.phase` /// - `.polar` /// - `init(r:θ:)` @_transparent public var length: RealType { - let naive = unsafeLengthSquared + let naive = lengthSquared guard naive.isNormal else { return carefulLength } return .sqrt(naive) } @@ -419,7 +419,7 @@ extension Complex { /// /// This property is more efficient to compute than `length`, but is /// highly prone to overflow or underflow; for finite values that are - /// not well-scaled, `unsafeLengthSquared` is often either zero or + /// not well-scaled, `lengthSquared` is often either zero or /// infinity, even when `length` is a finite number. Use this property /// only when you are certain that this value is well-scaled. /// @@ -431,10 +431,13 @@ extension Complex { /// - `.length` /// - `.magnitude` @_transparent - public var unsafeLengthSquared: RealType { + public var lengthSquared: RealType { x*x + y*y } + @available(*, unavailable, renamed: "lengthSquared") + public var unsafeLengthSquared: RealType { lengthSquared } + /// The phase (angle, or "argument"). /// /// Returns the angle (measured above the real axis) in radians. If @@ -484,9 +487,9 @@ extension Complex { /// ``` /// Complex(length: .zero, phase: θ) == .zero /// ``` - /// - For any `θ`, even `.infinity` or `.nan`: + /// - For any `θ`, even `.infinity` or `.nan`, if `r` is infinite then: /// ``` - /// Complex(length: .infinity, phase: θ) == .infinity + /// Complex(length: r, phase: θ) == .infinity /// ``` /// - Otherwise, `θ` must be finite, or a precondition failure occurs. /// @@ -501,8 +504,8 @@ extension Complex { self = Complex(.cos(phase), .sin(phase)).multiplied(by: length) } else { precondition( - length == 0 || length == .infinity, - "Either phase must be finite, or length must be zero or infinity." + length.isZero || length.isInfinite, + "Either phase must be finite, or length must be zero or infinite." ) self = Complex(length) } diff --git a/Tests/ComplexTests/ArithmeticTests.swift b/Tests/ComplexTests/ArithmeticTests.swift index f4bd0c46..de4c7e8d 100644 --- a/Tests/ComplexTests/ArithmeticTests.swift +++ b/Tests/ComplexTests/ArithmeticTests.swift @@ -67,12 +67,15 @@ final class ArithmeticTests: XCTestCase { // In order to support round-tripping from rectangular to polar coordinate // systems, as a special case phase can be non-finite when length is // either zero or infinity. - XCTAssertEqual(Complex(length: .zero, phase: .infinity), .zero) - XCTAssertEqual(Complex(length: .zero, phase: -.infinity), .zero) - XCTAssertEqual(Complex(length: .zero, phase: .nan ), .zero) - XCTAssertEqual(Complex(length: .infinity, phase: .infinity), .infinity) - XCTAssertEqual(Complex(length: .infinity, phase: -.infinity), .infinity) - XCTAssertEqual(Complex(length: .infinity, phase: .nan ), .infinity) + XCTAssertEqual(Complex(length: .zero, phase: .infinity), .zero) + XCTAssertEqual(Complex(length: .zero, phase:-.infinity), .zero) + XCTAssertEqual(Complex(length: .zero, phase: .nan ), .zero) + XCTAssertEqual(Complex(length: .infinity, phase: .infinity), .infinity) + XCTAssertEqual(Complex(length: .infinity, phase:-.infinity), .infinity) + XCTAssertEqual(Complex(length: .infinity, phase: .nan ), .infinity) + XCTAssertEqual(Complex(length:-.infinity, phase: .infinity), .infinity) + XCTAssertEqual(Complex(length:-.infinity, phase:-.infinity), .infinity) + XCTAssertEqual(Complex(length:-.infinity, phase: .nan ), .infinity) let exponentRange = (T.leastNormalMagnitude.exponent + T.Exponent(T.significandBitCount)) ... @@ -108,11 +111,11 @@ final class ArithmeticTests: XCTestCase { XCTFail() } XCTAssertEqual(w, -z) - // if length*length is normal, it should be unsafeLengthSquared, up + // if length*length is normal, it should be lengthSquared, up // to small error. if (p.length*p.length).isNormal { - if !closeEnough(z.unsafeLengthSquared, p.length*p.length, ulps: 16) { - print("p = \(p)\nz = \(z)\nz.unsafeLengthSquared = \(z.unsafeLengthSquared)") + if !closeEnough(z.lengthSquared, p.length*p.length, ulps: 16) { + print("p = \(p)\nz = \(z)\nz.lengthSquared = \(z.lengthSquared)") XCTFail() } }