Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry pick doc changes from main #193

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions Sources/ComplexModule/Arithmetic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,31 @@ extension Complex: AdditiveArithmetic {
// and turn these into operators if/when we have it.
// (https://github.com/apple/swift-numerics/issues/12)
extension Complex {
/// `self` scaled by `a`.
@usableFromInline @_transparent
internal func multiplied(by a: RealType) -> Complex {
// This can be viewed in two different ways, which are mathematically
// equivalent: either we are computing `self * Complex(a)` (i.e.
// converting `a` to be a complex value, and then using the complex
// multiplication) or we are using the scalar product of the vector
// space structure: `Complex(a*real, a*imaginary)`.
//
// Although these two interpretations are _mathematically_ equivalent,
// they will generate different representations of the point at
// infinity in general. For example, suppose `self` is represented by
// `(infinity, 0)`. Then `self * Complex(1)` would evaluate as
// `(1*infinity - 0*0, 0*infinity + 1*0) = (infinity, nan)`, but
// the vector space interpretation produces `(infinity, 0)`. This does
// not matter much, because these are two representations of the same
// semantic value, but note that one requires four multiplies and two
// additions, while the one we use requires only two real multiplications.
Complex(x*a, y*a)
}

/// `self` unscaled by `a`.
@usableFromInline @_transparent
internal func divided(by a: RealType) -> Complex {
// See implementation notes for `multiplied` above.
Complex(x/a, y/a)
}
}
Expand Down Expand Up @@ -145,19 +163,25 @@ extension Complex: AlgebraicField {
/// If z.reciprocal is non-nil, you can safely replace division by z with
/// multiplication by this value. It is not advantageous to do this for an
/// isolated division, but if you are dividing many values by a single
/// denominator, this will often be a significant performance win.
/// denominator, this may sometimes be a significant performance win.
///
/// Typical use looks like this:
/// A typical use case looks something like this:
/// ```
/// func divide<T: Real>(data: [Complex<T>], by divisor: Complex<T>) -> [Complex<T>] {
/// // If divisor is well-scaled, use multiply by reciprocal.
/// // If divisor is well-scaled, multiply by reciprocal.
/// if let recip = divisor.reciprocal {
/// return data.map { $0 * recip }
/// }
/// // Fallback on using division.
/// return data.map { $0 / divisor }
/// }
/// ```
///
/// Error Bounds:
///
/// Unlike real types, when working with complex types, multiplying by the
/// reciprocal instead of dividing cannot change the result. If the
/// reciprocal is non-nil, the two computations are always equivalent.
@inlinable
public var reciprocal: Complex? {
let recip = 1/self
Expand Down
29 changes: 24 additions & 5 deletions Sources/RealModule/AlgebraicField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,6 @@ public protocol AlgebraicField: SignedNumeric {
/// The (approximate) reciprocal (multiplicative inverse) of this number,
/// if it is representable.
///
/// If reciprocal is non-nil, you can replace division by self with
/// multiplication by reciprocal and either get exact the same result
/// (for finite fields) or approximately the same result up to a typical
/// rounding error (for floating-point formats).
///
/// If self is zero and the type has no representation for infinity (as
/// in a typical finite field implementation), or if a reciprocal would
/// overflow or underflow such that it cannot be accurately represented,
Expand All @@ -69,6 +64,30 @@ public protocol AlgebraicField: SignedNumeric {
/// Note that `.zero.reciprocal`, somewhat surprisingly, is *not* nil
/// for `Real` or `Complex` types, because these types have an
/// `.infinity` value that acts as the reciprocal of `.zero`.
///
/// If `x.reciprocal` is non-nil, you may be able to replace division by `x`
/// with multiplication by this value. It is not advantageous to do this
/// for an isolated division unless it is a compile-time constant visible
/// to the compiler, but if you are dividing many values by a single
/// denominator, this will often be a significant performance win.
///
/// Note that this will slightly perturb results for some fields with
/// approximate arithmetic, such as real types--using a normal division
/// is generally more accurate--but no catastrophic loss of accuracy will
/// result. For fields with exact arithmetic, or for the Complex types,
/// the results are identical.
///
/// A typical use case looks something like this:
/// ```
/// func divide<T: AlgebraicField>(data: [T], by divisor: T) -> [T] {
/// // If divisor is well-scaled, multiply by reciprocal.
/// if let recip = divisor.reciprocal {
/// return data.map { $0 * recip }
/// }
/// // Fallback on using division.
/// return data.map { $0 / divisor }
/// }
/// ```
var reciprocal: Self? { get }
}

Expand Down
46 changes: 44 additions & 2 deletions Sources/RealModule/Real.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,50 @@ extension Real {
/// The (approximate) reciprocal (multiplicative inverse) of this number,
/// if it is representable.
///
/// If `a` if finite and nonzero, and `1/a` overflows or underflows,
/// then `a.reciprocal` is `nil`. Otherwise, `a.reciprcoal` is `1/a`.
/// If `x` if finite and nonzero, and `1/x` overflows or underflows,
/// then `x.reciprocal` is `nil`. Otherwise, `a.reciprocal` is `1/x`.
///
/// If `x.reciprocal` is non-nil, you may be able to replace division by `x`
/// with multiplication by this value. It is not advantageous to do this
/// for an isolated division unless it is a compile-time constant visible
/// to the compiler, but if you are dividing many values by a single
/// denominator, this will often be a significant performance win.
///
/// A typical use case looks something like this:
/// ```
/// func divide<T: Real>(data: [T], by divisor: T) -> [T] {
/// // If divisor is well-scaled, multiply by reciprocal.
/// if let recip = divisor.reciprocal {
/// return data.map { $0 * recip }
/// }
/// // Fallback on using division.
/// return data.map { $0 / divisor }
/// }
/// ```
///
/// Error Bounds:
///
/// Multiplying by the reciprocal instead of dividing will slightly
/// perturb results. For example `5.0 / 3` is 1.6666666666666667, but
/// `5.0 * 3.reciprocal!` is 1.6666666666666665.
///
/// The error of a normal division is bounded by half an ulp of the
/// result; we can derive a quick error bound for multiplication by
/// the real reciprocal (when it exists) as follows (I will use circle
/// operators to denote real-number arithmetic, and normal operators
/// for floating-point arithmetic):
///
/// ```
/// a * b.reciprocal! = a * (1/b)
/// = a * (1 ⊘ b)(1 + δ₁)
/// = (a ⊘ b)(1 + δ₁)(1 + δ₂)
/// = (a ⊘ b)(1 + δ₁ + δ₂ + δ₁δ₂)
/// ```
///
/// where `0 < δᵢ <= ulpOfOne/2`. This gives a roughly 1-ulp error,
/// about twice the error bound we get using division. For most
/// purposes this is an acceptable error, but if you need to match
/// results obtained using division, you should not use this.
@inlinable
public var reciprocal: Self? {
let recip = 1/self
Expand Down