Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
68
Task/Approximate-equality/Swift/approximate-equality.swift
Normal file
68
Task/Approximate-equality/Swift/approximate-equality.swift
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import Foundation
|
||||
|
||||
extension FloatingPoint {
|
||||
@inlinable
|
||||
public func isAlmostEqual(
|
||||
to other: Self,
|
||||
tolerance: Self = Self.ulpOfOne.squareRoot()
|
||||
) -> Bool {
|
||||
// tolerances outside of [.ulpOfOne,1) yield well-defined but useless results,
|
||||
// so this is enforced by an assert rathern than a precondition.
|
||||
assert(tolerance >= .ulpOfOne && tolerance < 1, "tolerance should be in [.ulpOfOne, 1).")
|
||||
|
||||
// The simple computation below does not necessarily give sensible
|
||||
// results if one of self or other is infinite; we need to rescale
|
||||
// the computation in that case.
|
||||
guard self.isFinite && other.isFinite else {
|
||||
return rescaledAlmostEqual(to: other, tolerance: tolerance)
|
||||
}
|
||||
|
||||
// This should eventually be rewritten to use a scaling facility to be
|
||||
// defined on FloatingPoint suitable for hypot and scaled sums, but the
|
||||
// following is good enough to be useful for now.
|
||||
let scale = max(abs(self), abs(other), .leastNormalMagnitude)
|
||||
return abs(self - other) < scale*tolerance
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
internal func rescaledAlmostEqual(to other: Self, tolerance: Self) -> Bool {
|
||||
// NaN is considered to be not approximately equal to anything, not even
|
||||
// itself.
|
||||
if self.isNaN || other.isNaN { return false }
|
||||
if self.isInfinite {
|
||||
if other.isInfinite { return self == other }
|
||||
|
||||
// Self is infinite and other is finite. Replace self with the binade
|
||||
// of the greatestFiniteMagnitude, and reduce the exponent of other by
|
||||
// one to compensate.
|
||||
let scaledSelf = Self(sign: self.sign,
|
||||
exponent: Self.greatestFiniteMagnitude.exponent,
|
||||
significand: 1)
|
||||
let scaledOther = Self(sign: .plus,
|
||||
exponent: -1,
|
||||
significand: other)
|
||||
|
||||
// Now both values are finite, so re-run the naive comparison.
|
||||
return scaledSelf.isAlmostEqual(to: scaledOther, tolerance: tolerance)
|
||||
}
|
||||
|
||||
// If self is finite and other is infinite, flip order and use scaling
|
||||
// defined above, since this relation is symmetric.
|
||||
return other.rescaledAlmostEqual(to: self, tolerance: tolerance)
|
||||
}
|
||||
}
|
||||
|
||||
let testCases = [
|
||||
(100000000000000.01, 100000000000000.011),
|
||||
(100.01, 100.011),
|
||||
(10000000000000.001 / 10000.0, 1000000000.0000001000),
|
||||
(0.001, 0.0010000001),
|
||||
(0.000000000000000000000101, 0.0),
|
||||
(sqrt(2) * sqrt(2), 2.0),
|
||||
(-sqrt(2) * sqrt(2), -2.0),
|
||||
(3.14159265358979323846, 3.14159265358979324)
|
||||
]
|
||||
|
||||
for testCase in testCases {
|
||||
print("\(testCase.0), \(testCase.1) => \(testCase.0.isAlmostEqual(to: testCase.1))")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue