Skip to content

Commit e96f61c

Browse files
committed
Use elementsAlmostEqual to resolve suspected alignment-induced failures
`DoublePrecisionInterpolateBetweenNeighbours ` was occasionally faliing on tvOS simulator. Not using exact equality appears to have fixed this issue. The code I've used for `isAlmostEqual` is based on SE-0259
1 parent 85a3098 commit e96f61c

File tree

1 file changed

+96
-68
lines changed

1 file changed

+96
-68
lines changed

test/stdlib/Accelerate.swift

Lines changed: 96 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 4.0, *) {
7676

7777
if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
7878

79+
let n = 1024
80+
7981
AccelerateTests.test("vDSP/DiscreteCosineTransform") {
80-
let n = 1024
8182

8283
let source = (0 ..< n).map{ i in
8384
return sin(Float(i) * 0.05) + sin(Float(i) * 0.025)
@@ -109,19 +110,16 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
109110
source,
110111
&legacyDestination)
111112

112-
expectTrue(destination.elementsEqual(legacyDestination))
113-
expectTrue(destination.elementsEqual(returnedResult))
113+
expectTrue(elementsAlmostEqual(destination, legacyDestination))
114+
expectTrue(elementsAlmostEqual(destination, returnedResult))
114115
}
115116
}
116-
}
117-
118-
//===----------------------------------------------------------------------===//
119-
//
120-
// Sliding window summation
121-
//
122-
//===----------------------------------------------------------------------===//
123117

124-
if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
118+
//===----------------------------------------------------------------------===//
119+
//
120+
// Sliding window summation
121+
//
122+
//===----------------------------------------------------------------------===//
125123

126124
AccelerateTests.test("vDSP/SinglePrecisionSlidingWindowSum") {
127125
let source: [Float] = [1, 10, 12, 9, 3, 7, 2, 6]
@@ -134,7 +132,7 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
134132
let returnedResult = vDSP.slidingWindowSum(source,
135133
usingWindowLength: 3)
136134

137-
expectTrue(destination.elementsEqual(returnedResult))
135+
expectTrue(elementsAlmostEqual(destination, returnedResult))
138136
expectTrue(destination.map{ Int($0) }.elementsEqual([23, 31, 24, 19, 12, 15]))
139137
}
140138

@@ -149,22 +147,15 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
149147
let returnedResult = vDSP.slidingWindowSum(source,
150148
usingWindowLength: 3)
151149

152-
expectTrue(destination.elementsEqual(returnedResult))
153-
150+
expectTrue(elementsAlmostEqual(destination, returnedResult))
154151
expectTrue(destination.map{ Int($0) }.elementsEqual([23, 31, 24, 19, 12, 15]))
155152
}
156153

157-
}
158-
159-
//===----------------------------------------------------------------------===//
160-
//
161-
// Linear interpolation
162-
//
163-
//===----------------------------------------------------------------------===//
164-
165-
if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
166-
167-
let n = 1024
154+
//===----------------------------------------------------------------------===//
155+
//
156+
// Linear interpolation
157+
//
158+
//===----------------------------------------------------------------------===//
168159

169160
AccelerateTests.test("vDSP/SinglePrecisionInterpolateBetweenVectors") {
170161
var result = [Float](repeating: 0, count: n)
@@ -193,8 +184,8 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
193184
let returnedResult = vDSP.linearInterpolate(a, b,
194185
using: interpolationConstant)
195186

196-
expectTrue(result.elementsEqual(legacyResult))
197-
expectTrue(result.elementsEqual(returnedResult))
187+
expectTrue(elementsAlmostEqual(result, legacyResult))
188+
expectTrue(elementsAlmostEqual(result, returnedResult))
198189
}
199190

200191
AccelerateTests.test("vDSP/SinglePrecisionInterpolateBetweenNeighbours") {
@@ -229,8 +220,8 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
229220
let returnedResult = vDSP.linearInterpolate(elementsOf: shortSignal,
230221
using: controlVector)
231222

232-
expectTrue(result.elementsEqual(legacyResult))
233-
expectTrue(result.elementsEqual(returnedResult))
223+
expectTrue(elementsAlmostEqual(result, legacyResult))
224+
expectTrue(elementsAlmostEqual(result, returnedResult))
234225
}
235226

236227
AccelerateTests.test("vDSP/DoublePrecisionInterpolateBetweenVectors") {
@@ -260,8 +251,8 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
260251
let returnedResult = vDSP.linearInterpolate(a, b,
261252
using: interpolationConstant)
262253

263-
expectTrue(result.elementsEqual(legacyResult))
264-
expectTrue(result.elementsEqual(returnedResult))
254+
expectTrue(elementsAlmostEqual(result, legacyResult))
255+
expectTrue(elementsAlmostEqual(result, returnedResult))
265256
}
266257

267258
AccelerateTests.test("vDSP/DoublePrecisionInterpolateBetweenNeighbours") {
@@ -296,19 +287,16 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
296287
let returnedResult = vDSP.linearInterpolate(elementsOf: shortSignal,
297288
using: controlVector)
298289

299-
expectTrue(result.elementsEqual(legacyResult))
300-
expectTrue(result.elementsEqual(returnedResult))
290+
expectTrue(elementsAlmostEqual(result, legacyResult))
291+
expectTrue(elementsAlmostEqual(result, returnedResult))
301292
}
302-
}
303293

304-
//===----------------------------------------------------------------------===//
305-
//
306-
// vDSP difference equation
307-
//
308-
//===----------------------------------------------------------------------===//
294+
//===----------------------------------------------------------------------===//
295+
//
296+
// vDSP difference equation
297+
//
298+
//===----------------------------------------------------------------------===//
309299

310-
if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
311-
312300
AccelerateTests.test("vDSP/DifferenceEquationSinglePrecision") {
313301
let n = 256
314302

@@ -343,8 +331,8 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
343331
coefficients[3],
344332
coefficients[4]))
345333

346-
expectTrue(result.elementsEqual(legacyResult))
347-
expectTrue(result.elementsEqual(returnedResult))
334+
expectTrue(elementsAlmostEqual(result, legacyResult))
335+
expectTrue(elementsAlmostEqual(result, returnedResult))
348336
}
349337

350338
AccelerateTests.test("vDSP/DifferenceEquationDoublePrecision") {
@@ -381,18 +369,16 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
381369
coefficients[3],
382370
coefficients[4]))
383371

384-
expectTrue(result.elementsEqual(legacyResult))
385-
expectTrue(result.elementsEqual(returnedResult))
372+
expectTrue(elementsAlmostEqual(result, legacyResult))
373+
expectTrue(elementsAlmostEqual(result, returnedResult))
386374
}
387-
}
388375

389-
//===----------------------------------------------------------------------===//
390-
//
391-
// vDSP downsampling
392-
//
393-
//===----------------------------------------------------------------------===//
376+
//===----------------------------------------------------------------------===//
377+
//
378+
// vDSP downsampling
379+
//
380+
//===----------------------------------------------------------------------===//
394381

395-
if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
396382
AccelerateTests.test("vDSP/DownsampleSinglePrecision") {
397383
let decimationFactor = 2
398384
let filterLength: vDSP_Length = 2
@@ -429,8 +415,8 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
429415
decimationFactor: decimationFactor,
430416
filter: filter)
431417

432-
expectTrue(result.elementsEqual(legacyResult))
433-
expectTrue(result.elementsEqual(returnedResult))
418+
expectTrue(elementsAlmostEqual(result, legacyResult))
419+
expectTrue(elementsAlmostEqual(result, returnedResult))
434420
}
435421

436422
AccelerateTests.test("vDSP/DownsampleDoublePrecision") {
@@ -469,19 +455,16 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
469455
decimationFactor: decimationFactor,
470456
filter: filter)
471457

472-
expectTrue(result.elementsEqual(legacyResult))
473-
expectTrue(result.elementsEqual(returnedResult))
458+
expectTrue(elementsAlmostEqual(result, legacyResult))
459+
expectTrue(elementsAlmostEqual(result, returnedResult))
474460
}
475-
}
476461

477-
//===----------------------------------------------------------------------===//
478-
//
479-
// vDSP polynomial evaluation.
480-
//
481-
//===----------------------------------------------------------------------===//
462+
//===----------------------------------------------------------------------===//
463+
//
464+
// vDSP polynomial evaluation.
465+
//
466+
//===----------------------------------------------------------------------===//
482467

483-
if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
484-
485468
AccelerateTests.test("vDSP/PolynomialEvaluationSinglePrecision") {
486469
let coefficients: [Float] = [2, 3, 4, 5, 6, 7, 8, 9, 10]
487470
let variables = (0 ... 100).map { return Float($0) }
@@ -502,8 +485,8 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
502485
let returnedResult = vDSP.evaluatePolynomial(usingCoefficients: coefficients,
503486
withVariables: variables)
504487

505-
expectTrue(result.elementsEqual(legacyResult))
506-
expectTrue(result.elementsEqual(returnedResult))
488+
expectTrue(elementsAlmostEqual(result, legacyResult))
489+
expectTrue(elementsAlmostEqual(result, returnedResult))
507490
}
508491

509492
AccelerateTests.test("vDSP/PolynomialEvaluationDoublePrecision") {
@@ -526,8 +509,53 @@ if #available(iOS 9999, macOS 9999, tvOS 9999, watchOS 9999, *) {
526509
let returnedResult = vDSP.evaluatePolynomial(usingCoefficients: coefficients,
527510
withVariables: variables)
528511

529-
expectTrue(result.elementsEqual(legacyResult))
530-
expectTrue(result.elementsEqual(returnedResult))
512+
expectTrue(elementsAlmostEqual(result, legacyResult))
513+
expectTrue(elementsAlmostEqual(result, returnedResult))
514+
}
515+
516+
//===----------------------------------------------------------------------===//
517+
//
518+
// Array almost equal.
519+
//
520+
//===----------------------------------------------------------------------===//
521+
522+
func elementsAlmostEqual<T: FloatingPoint>(_ lhs: [T], _ rhs: [T]) -> Bool {
523+
var returnValue = true
524+
zip(lhs, rhs).forEach {
525+
if !isAlmostEqual($0.0, $0.1) {
526+
returnValue = false
527+
return
528+
}
529+
}
530+
return returnValue
531+
}
532+
533+
func isAlmostEqual<T: FloatingPoint>(_ lhs: T,
534+
_ rhs: T,
535+
tolerance: T = T.ulpOfOne.squareRoot()) -> Bool {
536+
assert(tolerance >= .ulpOfOne && tolerance < 1, "tolerance should be in [.ulpOfOne, 1).")
537+
guard lhs.isFinite && rhs.isFinite else {
538+
return rescaledAlmostEqual(lhs, rhs, tolerance: tolerance)
539+
}
540+
let scale = max(abs(lhs), abs(rhs), .leastNormalMagnitude)
541+
return abs(lhs - rhs) < scale*tolerance
542+
}
543+
544+
func rescaledAlmostEqual<T: FloatingPoint>(_ lhs: T,
545+
_ rhs: T,
546+
tolerance: T) -> Bool {
547+
if lhs.isNaN || rhs.isNaN { return false }
548+
if lhs.isInfinite {
549+
if rhs.isInfinite { return lhs == rhs }
550+
let scaledLhs = T(sign: lhs.sign,
551+
exponent: T.greatestFiniteMagnitude.exponent,
552+
significand: 1)
553+
let scaledRhs = T(sign: .plus,
554+
exponent: -1,
555+
significand: rhs)
556+
return isAlmostEqual(scaledLhs, scaledRhs, tolerance: tolerance)
557+
}
558+
return rescaledAlmostEqual(rhs, lhs, tolerance: tolerance)
531559
}
532560
}
533561

0 commit comments

Comments
 (0)