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