Skip to content

Add isApproximatelyEqual for RandomAccessCollection #334

Description

@jkrukowski

I think it would be useful to add isApproximatelyEqual for RandomAccessCollection. When working with numerical computations on collections of floating-point values (e.g., vectors, matrices represented as arrays), it's common in tests to need element-wise approximate equality comparisons. The API would mirror the existing scalar versions:

extension RandomAccessCollection where Element: Numeric, Element.Magnitude: FloatingPoint {
  @inlinable @inline(__always)
  public func isApproximatelyEqual(
    to other: Self,
    relativeTolerance: Element.Magnitude = Element.Magnitude.ulpOfOne.squareRoot(),
    norm: (Element) -> Element.Magnitude = \.magnitude
  ) -> Bool {
    return isApproximatelyEqual(
      to: other,
      absoluteTolerance: relativeTolerance * Element.Magnitude.leastNormalMagnitude,
      relativeTolerance: relativeTolerance,
      norm: norm
    )
  }

  @inlinable @inline(__always)
  public func isApproximatelyEqual(
    to other: Self,
    absoluteTolerance: Element.Magnitude,
    relativeTolerance: Element.Magnitude = 0
  ) -> Bool {
    return isApproximatelyEqual(
      to: other,
      absoluteTolerance: absoluteTolerance,
      relativeTolerance: relativeTolerance,
      norm: \.magnitude
    )
  }
}

extension RandomAccessCollection where Element: AdditiveArithmetic {
  @inlinable
  public func isApproximatelyEqual<Magnitude>(
    to other: Self,
    absoluteTolerance: Magnitude,
    relativeTolerance: Magnitude = 0,
    norm: (Element) -> Magnitude
  ) -> Bool
  where Magnitude: FloatingPoint {
    guard self.count == other.count else { return false }
    for (lhs, rhs) in zip(self, other) {
      if !lhs.isApproximatelyEqual(
        to: rhs,
        absoluteTolerance: absoluteTolerance,
        relativeTolerance: relativeTolerance,
        norm: norm
      ) {
        return false
      }
    }
    return true
  }
}

I'm happy to submit a PR with tests if this sounds reasonable.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions