1- //===--- ElementaryFunctionTests .swift ------------------------*- swift -*-===//
1+ //===--- ElementaryFunctionChecks .swift ------------------------*- swift -*-===//
22//
33// This source file is part of the Swift Numerics open source project
44//
@@ -22,28 +22,42 @@ func sanityCheck<T>(_ expected: TestLiteralType, _ actual: T,
2222 ulps allowed: T = 16 ,
2323 file: StaticString = #file, line: UInt = #line)
2424 where T: BinaryFloatingPoint {
25+ // Shortcut relative-error check if we got the sign wrong; it's OK to
26+ // underflow to zero a little bit early, but we don't want to allow going
27+ // right through zero to the other side.
28+ XCTAssert ( actual. sign == expected. sign, " \( actual) != \( expected) as \( T . self) " , file: file, line: line)
2529 // Default tolerance is 16 ulps; It's OK to relax this as needed for new
26- // platforms, as these tests are *not* intended to validate the math
30+ // platforms, as these checks are *not* intended to validate the math
2731 // library--they are only intended to check that the Swift bindings are
2832 // calling the right functions in the math library. It's important, however
29- // not to relax the tolerance beyond a few hundred ulps, because these tests
33+ // not to relax the tolerance beyond a few hundred ulps, because these checks
3034 // need to detect errors where the *wrong function* is being called; e.g.
3135 // we need to flag an implentation that inadvertently called the C hypotf
3236 // function instead of hypot. This is especially important because the C
3337 // shims that we're calling through will allow silent type conversions.
3438 if actual == T ( expected) || actual. isNaN && expected. isNaN {
3539 return
3640 }
37- // Compute error in ulp, compare to tolerance.
38- let absoluteError = T ( abs ( TestLiteralType ( actual) - expected) )
39- let ulpError = absoluteError / T( expected) . ulp
40- XCTAssert ( ulpError <= allowed, " \( actual) != \( expected) as \( T . self) " +
41- " \n \( ulpError) -ulp error exceeds \( allowed) -ulp tolerance. " ,
42- file: file, line: line)
41+ // Special-case where expected or observed is infinity.
42+ // Artificially knock everything down a binade, treat actual infinity as
43+ // the base of the next binade up.
44+ if actual. isInfinite || T ( expected) . isInfinite {
45+ let scaledExpected = TestLiteralType ( signOf: expected,
46+ magnitudeOf: expected. isInfinite ? TestLiteralType . greatestFiniteMagnitude. binade : 0.5 * expected
47+ )
48+ let scaledActual = T ( signOf: actual,
49+ magnitudeOf: actual. isInfinite ? T . greatestFiniteMagnitude. binade : 0.5 * actual
50+ )
51+ return sanityCheck ( scaledExpected, scaledActual, ulps: allowed, file: file, line: line)
52+ }
53+ // Compute error in ulp, compare to tolerance.
54+ let absoluteError = T ( abs ( TestLiteralType ( actual) - expected) ) . magnitude
55+ let ulpError = absoluteError / max( T ( expected) . magnitude, T . leastNormalMagnitude) . ulp
56+ XCTAssert ( ulpError <= allowed, " \( actual) != \( expected) as \( T . self) \n \( ulpError) -ulp error exceeds \( allowed) -ulp tolerance. " , file: file, line: line)
4357}
4458
4559internal extension ElementaryFunctions where Self: BinaryFloatingPoint {
46- static func elementaryFunctionTests ( ) {
60+ static func elementaryFunctionChecks ( ) {
4761 sanityCheck ( 1.1863995522992575361931268186727044683 , Self . acos ( 0.375 ) )
4862 sanityCheck ( 0.3843967744956390830381948729670469737 , Self . asin ( 0.375 ) )
4963 sanityCheck ( 0.3587706702705722203959200639264604997 , Self . atan ( 0.375 ) )
@@ -69,7 +83,7 @@ internal extension ElementaryFunctions where Self: BinaryFloatingPoint {
6983}
7084
7185internal extension Real where Self: BinaryFloatingPoint {
72- static func realFunctionTests ( ) {
86+ static func realFunctionChecks ( ) {
7387 sanityCheck ( 1.2968395546510096659337541177924511598 , Self . exp2 ( 0.375 ) )
7488 sanityCheck ( 2.3713737056616552616517527574788898386 , Self . exp10 ( 0.375 ) )
7589 sanityCheck ( - 1.415037499278843818546261056052183491 , Self . log2 ( 0.375 ) )
@@ -85,25 +99,121 @@ internal extension Real where Self: BinaryFloatingPoint {
8599 XCTAssertEqual ( . minus, Self . signGamma ( - 2.375 ) )
86100 #endif
87101 }
102+
103+ static func testPownCommon( ) {
104+ // If x is -1, then the result is ±1 with sign chosen by parity of n.
105+ // Simply converting n to Real will flip parity when n is large, so
106+ // first check that we get those cases right.
107+ XCTAssertEqual ( Self . pow ( - 1 , 0 ) , 1 )
108+ XCTAssertEqual ( Self . pow ( - 1 , 1 ) , - 1 )
109+ XCTAssertEqual ( Self . pow ( - 1 , - 1 ) , - 1 )
110+ XCTAssertEqual ( Self . pow ( - 1 , 2 ) , 1 )
111+ XCTAssertEqual ( Self . pow ( - 1 , - 2 ) , 1 )
112+ XCTAssertEqual ( Self . pow ( - 1 , Int . max - 1 ) , 1 )
113+ XCTAssertEqual ( Self . pow ( - 1 , - Int. max + 1 ) , 1 )
114+ XCTAssertEqual ( Self . pow ( - 1 , Int . max) , - 1 )
115+ XCTAssertEqual ( Self . pow ( - 1 , - Int. max) , - 1 )
116+ XCTAssertEqual ( Self . pow ( - 1 , Int . min) , 1 )
117+ }
118+ }
119+
120+ extension Float {
121+ static func testPown( ) {
122+ testPownCommon ( )
123+ let u = Float ( 1 ) . nextUp
124+ let d = Float ( 1 ) . nextDown
125+ // Smallest exponents not exactly representable as Float.
126+ sanityCheck ( - 7.3890560989306677280287919329569359 , Float . pow ( - u, 0x1000001 ) )
127+ sanityCheck ( - 0.3678794082804575860056608283059288 , Float . pow ( - d, 0x1000001 ) )
128+ // Exponents close to overflow boundary.
129+ sanityCheck ( - 3.4028231352500001570898203463449749e38 , Float . pow ( - u, 744261161 ) )
130+ sanityCheck ( 3.4028235408981285772043562848249166e38 , Float . pow ( - u, 744261162 ) )
131+ sanityCheck ( - 3.4028239465463053543440887892352174e38 , Float . pow ( - u, 744261163 ) )
132+ sanityCheck ( 3.4028233551634475284795244782720072e38 , Float . pow ( - d, - 1488522190 ) )
133+ sanityCheck ( - 3.4028235579875369356575053576685267e38 , Float . pow ( - d, - 1488522191 ) )
134+ sanityCheck ( 3.4028237608116384320940078199368685e38 , Float . pow ( - d, - 1488522192 ) )
135+ // Exponents close to underflow boundary.
136+ sanityCheck ( 7.0064936491761438872280296737844625e-46 , Float . pow ( - u, - 872181048 ) )
137+ sanityCheck ( - 7.0064928139371132951305928725186420e-46 , Float . pow ( - u, - 872181049 ) )
138+ sanityCheck ( 7.0064919786981822712727285793333389e-46 , Float . pow ( - u, - 872181050 ) )
139+ sanityCheck ( - 7.0064924138100205091278464932003585e-46 , Float . pow ( - d, 1744361943 ) )
140+ sanityCheck ( 7.0064919961905290625123586120258840e-46 , Float . pow ( - d, 1744361944 ) )
141+ sanityCheck ( - 7.0064915785710625079583096856510544e-46 , Float . pow ( - d, 1744361945 ) )
142+ // Just hammer max/min exponents, these always saturate, but this will reveal
143+ // errors in some implementations that one could try.
144+ sanityCheck ( . infinity, Self . pow ( - u, Int . max - 1 ) )
145+ sanityCheck ( 0.0 , Self . pow ( - d, Int . max - 1 ) )
146+ sanityCheck ( 0.0 , Self . pow ( - u, - Int. max + 1 ) )
147+ sanityCheck ( . infinity, Self . pow ( - d, - Int. max + 1 ) )
148+ sanityCheck ( - . infinity, Self . pow ( - u, Int . max) )
149+ sanityCheck ( - 0.0 , Self . pow ( - d, Int . max) )
150+ sanityCheck ( - 0.0 , Self . pow ( - u, - Int. max) )
151+ sanityCheck ( - . infinity, Self . pow ( - d, - Int. max) )
152+ sanityCheck ( 0.0 , Self . pow ( - u, Int . min) )
153+ sanityCheck ( . infinity, Self . pow ( - d, Int . min) )
154+ }
88155}
89156
90- final class ElementaryFunctionTests : XCTestCase {
157+ extension Double {
158+ static func testPown( ) {
159+ testPownCommon ( )
160+ // Following tests only make sense (and are only necessary) on 64b platforms.
161+ #if arch(arm64) || arch(x86_64)
162+ let u : Double = 1 . nextUp
163+ let d : Double = 1 . nextDown
164+ // Smallest exponent not exactly representable as Double.
165+ sanityCheck ( - 7.3890560989306502272304274605750685 , Double . pow ( - u, 0x20000000000001 ) )
166+ sanityCheck ( - 0.1353352832366126918939994949724833 , Double . pow ( - u, - 0x20000000000001 ) )
167+ sanityCheck ( - 0.3678794411714422603312898889458068 , Double . pow ( - d, 0x20000000000001 ) )
168+ sanityCheck ( - 2.7182818284590456880451484776630468 , Double . pow ( - d, - 0x20000000000001 ) )
169+ // Exponents close to overflow boundary.
170+ sanityCheck ( 1.7976931348623151738531864721534215e308 , Double . pow ( - u, 3196577161300664268 ) )
171+ sanityCheck ( - 1.7976931348623155730212483790972209e308 , Double . pow ( - u, 3196577161300664269 ) )
172+ sanityCheck ( 1.7976931348623159721893102860411089e308 , Double . pow ( - u, 3196577161300664270 ) )
173+ sanityCheck ( 1.7976931348623157075547244136070910e308 , Double . pow ( - d, - 6393154322601327474 ) )
174+ sanityCheck ( - 1.7976931348623159071387553670790721e308 , Double . pow ( - d, - 6393154322601327475 ) )
175+ sanityCheck ( 1.7976931348623161067227863205510754e308 , Double . pow ( - d, - 6393154322601327476 ) )
176+ // Exponents close to underflow boundary.
177+ sanityCheck ( 2.4703282292062334560337346683707907e-324 , Double . pow ( - u, - 3355781687888880946 ) )
178+ sanityCheck ( - 2.4703282292062329075106789791206172e-324 , Double . pow ( - u, - 3355781687888880947 ) )
179+ sanityCheck ( 2.4703282292062323589876232898705654e-324 , Double . pow ( - u, - 3355781687888880948 ) )
180+ sanityCheck ( - 2.4703282292062332640976590913373022e-324 , Double . pow ( - d, 6711563375777760775 ) )
181+ sanityCheck ( 2.4703282292062329898361312467121758e-324 , Double . pow ( - d, 6711563375777760776 ) )
182+ sanityCheck ( - 2.4703282292062327155746034020870799e-324 , Double . pow ( - d, 6711563375777760777 ) )
183+ // Just hammer max/min exponents, these always saturate, but this will reveal
184+ // errors in some implementations that one could try.
185+ sanityCheck ( . infinity, Self . pow ( - u, Int . max - 1 ) )
186+ sanityCheck ( 0.0 , Self . pow ( - d, Int . max - 1 ) )
187+ sanityCheck ( 0.0 , Self . pow ( - u, - Int. max + 1 ) )
188+ sanityCheck ( . infinity, Self . pow ( - d, - Int. max + 1 ) )
189+ sanityCheck ( - . infinity, Self . pow ( - u, Int . max) )
190+ sanityCheck ( - 0.0 , Self . pow ( - d, Int . max) )
191+ sanityCheck ( - 0.0 , Self . pow ( - u, - Int. max) )
192+ sanityCheck ( - . infinity, Self . pow ( - d, - Int. max) )
193+ sanityCheck ( 0.0 , Self . pow ( - u, Int . min) )
194+ sanityCheck ( . infinity, Self . pow ( - d, Int . min) )
195+ #endif
196+ }
197+ }
198+
199+ final class ElementaryFunctionChecks : XCTestCase {
91200
92201 func testFloat( ) {
93- Float . elementaryFunctionTests ( )
94- Float . realFunctionTests ( )
202+ Float . elementaryFunctionChecks ( )
203+ Float . realFunctionChecks ( )
204+ Float . testPown ( )
95205 }
96206
97207 func testDouble( ) {
98- Double . elementaryFunctionTests ( )
99- Double . realFunctionTests ( )
208+ Double . elementaryFunctionChecks ( )
209+ Double . realFunctionChecks ( )
210+ Double . testPown ( )
100211 }
101212
102-
103213 #if (arch(i386) || arch(x86_64)) && !os(Windows) && !os(Android)
104214 func testFloat80( ) {
105- Float80 . elementaryFunctionTests ( )
106- Float80 . realFunctionTests ( )
215+ Float80 . elementaryFunctionChecks ( )
216+ Float80 . realFunctionChecks ( )
107217 }
108218 #endif
109219}
0 commit comments