this repo has no description
at fixPythonPipStalling 394 lines 20 kB view raw
1/* 2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22/******************************************************************************* 23* * 24* File erfcerf.c, * 25* Functions erf(x) and cerf(x), * 26* Implementation of the error and complementary error function for the * 27* PowerPC. * 28* * 29* Copyright c 1993 Apple Computer, Inc. All rights reserved. * 30* * 31* Written by Ali Sazegari, started on February 1993, * 32* * 33* based on FORTRAN routines in SpecFun by J. W. Cody of Applied * 34* Mathematics Division of Argonne National Laboratory, Argonne, IL * 35* 60439. * 36* * 37* W A R N I N G: This routine expects a 64 bit double model. * 38* * 39* February 22 1993: First C implementation for PowerPC. * 40* July 14 1993: added #pragma fenv_access, declared variables * 41* register automatics, changed feholdexcept to the * 42* internal MathLib function _feprocentry. * 43* October 07 1993: corrected the return of signed zero in erf. * 44* September 19 1994: replaced the environmental enquiries by __setflm. * 45* October 31 1995: corrected an error in the computation of erfc in * 46* the interval of [-0.46875,0.0]. changed the value * 47* of xbig to disallow flush to zero. * 48* November 01 1995: corrected an undeserved underfow flag in erf. * 49* * 50******************************************************************************** 51* * 52* E R F ( X ) & C E R F ( X ) * 53* * 54******************************************************************************** 55* * 56* Explanation of machine-dependent constants: * 57* * 58* xmin = the smallest positive floating-point number. * 59* xneg = the largest negative argument acceptable to ERFCX; * 60* the negative of the solution to the equation * 61* 2 * exp ( x * x ) = HUGE_VAL. * 62* xsmall = argument below which erf(x) may be represented by * 63* 2 * x / sqrt ( pi ) and above which x * x will not * 64* underflow. A conservative value is the largest machine * 65* number x such that 1.0 + x = 1.0 to machine precision. * 66* xbig = largest argument acceptable to erfc; solution to * 67* the equation: W(x) * ( 1 - 0.5 / x ** 2 ) = xmin, where * 68* W(x) = exp ( - x * x ) / ( x * sqrt ( pi ) ). * 69* HUGE = argument above which 1 - 1 / ( 2 * x * x ) = 1 to * 70* machine precision. A conservative value is * 71* 1 / ( 2 * sqrt ( xsmall ) ) . * 72* Maximum = largest acceptable argument to erfcx; the minimum * 73* of HUGE_VAL and 1 / ( sqrt ( pi ) * xmin ). * 74* * 75* Approximate values for the macintosh and the powerpc are: * 76* * 77* xmin xinf xneg xsmall * 78* * 79* Macintosh (E.P.) * 80* PowerPC (D.P.) 2.23D-308 1.79D+308 -26.628 1.11D-16 * 81* * 82* xbig HUGE Maximum * 83* * 84* Macintosh (E.P.) * 85* PowerPC (D.P.) 26.543 6.71D+7 2.53D+307 * 86* if not flush to 0 27.2 * 87* * 88******************************************************************************** 89* * 90* Functions required are: * 91* * 92* Transandental: exp; * 93* Auxiliary: trunc, fabs and __fpclassifyd; * 94* Environmental: feholdexcept and feupdateenv. * 95* * 96* Reference: * 97* * 98* The main computation evaluates near-minimax approximations * 99* from "Rational Chebyshev approximations for the error function" * 100* by W. J. Cody, Math. Comp., 1969, PP. 631-638. * 101* * 102* This program uses rational functions that theoretically approximate * 103* erf(x) and erfc(x) to at least 18 significant decimal digits. * 104* * 105*******************************************************************************/ 106 107#include "math.h" 108#include "fenv.h" 109#include "fp_private.h" 110#include "fenv_private.h" 111 112#define EXCEPT_MASK 0x1ff80000 113 114/******************************************************************************* 115* Functions needed for the computation. * 116*******************************************************************************/ 117 118/* the following fp.h functions are used: */ 119/* __fpclassifyd, copysign, trunc, fabs and exp; */ 120/* the following environmental functions are used: */ 121/* __setflm. */ 122 123/******************************************************************************* 124* Coefficients for approximation to erf in [ -0.46875, 0.46875] in * 125* decreasing order. * 126*******************************************************************************/ 127 128static const double a[5] = { 3.16112374387056560e+0, 129 1.13864154151050156e+2, 130 3.77485237685302021e+2, 131 3.20937758913846947e+3, 132 1.85777706184603153e-1 }; 133 134static const double b[4] = { 2.36012909523441209e+1, 135 2.44024637934444173e+2, 136 1.28261652607737228e+3, 137 2.84423683343917062e+3 }; 138 139/******************************************************************************* 140* Coefficients for approximation to erfc in [-4.0,-0.46875)U(0.46875,4.0] * 141* in decreasing order. * 142*******************************************************************************/ 143 144static const double c[9] = { 5.64188496988670089e-1, 145 8.88314979438837594e+0, 146 6.61191906371416295e+1, 147 2.98635138197400131e+2, 148 8.81952221241769090e+2, 149 1.71204761263407058e+3, 150 2.05107837782607147e+3, 151 1.23033935479799725e+3, 152 2.15311535474403846e-8 }; 153 154static const double d[8] = { 1.57449261107098347e+1, 155 1.17693950891312499e+2, 156 5.37181101862009858e+2, 157 1.62138957456669019e+3, 158 3.29079923573345963e+3, 159 4.36261909014324716e+3, 160 3.43936767414372164e+3, 161 1.23033935480374942e+3 }; 162 163/******************************************************************************* 164* Coefficients for approximation to erfc in [-inf,-4.0)U(4.0,inf] in * 165* decreasing order. * 166*******************************************************************************/ 167 168static const double p[6] = { 3.05326634961232344e-1, 169 3.60344899949804439e-1, 170 1.25781726111229246e-1, 171 1.60837851487422766e-2, 172 6.58749161529837803e-4, 173 1.63153871373020978e-2 }; 174 175static const double q[5] = { 2.56852019228982242e+0, 176 1.87295284992346047e+0, 177 5.27905102951428412e-1, 178 6.05183413124413191e-2, 179 2.33520497626869185e-3 }; 180 181static const double InvSqrtPI = 5.6418958354775628695e-1; 182static const double xbig = 27.2e+0; 183static const double Maximum = 2.53e+307; 184static const double _HUGE = 6.71e+7; 185 186#pragma STDC FENV_ACCESS ON 187 188static double ErrFunApprox ( double arg, double result, int which ); 189 190/******************************************************************************* 191* E R R O R F U N C T I O N * 192*******************************************************************************/ 193 194double erf ( double x ) 195 { 196 register int which = 0; 197 register double result = 0.0; 198 hexdouble OldEnvironment, NewEnvironment; 199 200/******************************************************************************* 201* The next switch will decipher what sort of argument we have. If argument * 202* is SNaN then a QNaN has to be returned and the invalid flag signaled. * 203*******************************************************************************/ 204 205 switch ( __fpclassifyd ( x ) ) 206 { 207 case FP_NAN: 208 x *= 2.0; /* Sets invalid & quiets NaN */ 209 return x; 210 case FP_ZERO: 211 return x; 212 case FP_INFINITE: 213 return (x > 0.0 ? 1.0 : - 1.0); 214 default: /* NORMALNUM and DENORMALNUM */ 215 break; 216 } 217 218 FEGETENVD( OldEnvironment.d ); // save environment, set default 219 FESETENVD( 0.0 ); 220 221 result = 1.0; 222 result = ErrFunApprox ( x, result, which ); 223 224/******************************************************************************* 225* Take care of the negative argument. * 226*******************************************************************************/ 227 228 result = copysign ( result, x); 229 230 FEGETENVD( NewEnvironment.d ); 231 OldEnvironment.i.lo |= ( NewEnvironment.i.lo & EXCEPT_MASK ); // Merge new exceptions into old environment 232 FESETENVD( OldEnvironment.d ); // restore caller's environment 233 234 return ( result ); 235 } 236 237/******************************************************************************* 238* C O M P L E M E N T A R Y E R R O R F U N C T I O N * 239*******************************************************************************/ 240 241double erfc ( double x ) 242 { 243 register int which = 1; 244 register double result = 0.0; 245 hexdouble OldEnvironment, NewEnvironment; 246 247 248/******************************************************************************* 249* The next switch will decipher what sort of argument we have. If argument * 250* is SNaN then a QNaN has to be returned and the invalid flag signaled. * 251*******************************************************************************/ 252 253 switch ( __fpclassifyd ( x ) ) 254 { 255 case FP_NAN: 256 x *= 2.0; /* Sets invalid & quiets NaN */ 257 return x; 258 case FP_ZERO: 259 return 1.0; 260 case FP_INFINITE: 261 return (x > 0.0 ? 0.0 : 2.0); 262 default: /* NORMALNUM and DENORMALNUM */ 263 break; 264 } 265 266 FEGETENVD( OldEnvironment.d ); // save environment, set default 267 FESETENVD( 0.0 ); 268 269 result = 0.0; 270 result = ErrFunApprox ( x, result, which ); 271 272/******************************************************************************* 273* Take care of the negative argument. * 274*******************************************************************************/ 275 276 if ( x < 0.0 ) 277 result = 2.0 - result; 278 279 FEGETENVD( NewEnvironment.d ); 280 OldEnvironment.i.lo |= ( NewEnvironment.i.lo & EXCEPT_MASK ); // Merge new exceptions into old environment 281 FESETENVD( OldEnvironment.d ); // restore caller's environment 282 283 return ( result ); 284 } 285 286 287/******************************************************************************* 288* C O R E A P P R O X I M A T I O N * 289*******************************************************************************/ 290 291static double ErrFunApprox ( double arg, double result, int which ) 292 { 293 register int i; 294 register double x, y, ysquared, numerator, denominator, del; 295 296 x = arg; 297 y = fabs ( x ); 298 299/******************************************************************************* 300* Evaluate erfc for |x| <= 0.46875. * 301*******************************************************************************/ 302 303 if ( y <= 0.46875e+0 ) 304 { 305 ysquared = 0.0; 306 if ( y > 1.11e-16 ) 307 ysquared = y * y; 308 numerator = a[4] * ysquared; 309 denominator = ysquared; 310 for ( i = 0; i < 3; i++ ) 311 { 312 numerator = ( numerator + a[i] ) * ysquared; 313 denominator = ( denominator + b[i] ) * ysquared; 314 } 315 result = y * ( numerator + a[3] ) / ( denominator + b[3] ); 316 if ( which ) result = 1.0 - result; 317 return result; 318 } 319 320/******************************************************************************* 321* Evaluate erfc for 0.46875 < |x| <= 4.0 * 322*******************************************************************************/ 323 324 else if ( y <= 4.0 ) 325 { 326 numerator = c[8] * y; 327 denominator = y; 328 for ( i = 0; i < 7; i++ ) 329 { 330 numerator = ( numerator + c[i] ) * y; 331 denominator = ( denominator + d[i] ) * y; 332 } 333 result = ( numerator + c[7] ) / ( denominator + d[7] ); 334 ysquared = trunc ( y * 16.0 ) / 16.0; 335 del = ( y - ysquared ) * ( y + ysquared ); 336 result = exp ( - ysquared * ysquared ) * exp ( - del ) * result; 337 } 338 339/******************************************************************************* 340* Evaluate erfc for |x| > 4.0 * 341*******************************************************************************/ 342 343 else 344 { 345 if ( y >= xbig ) 346 { 347 if ( ( which != 2 ) || ( y >= Maximum ) ) 348 { 349 if ( which == 1 ) 350 { 351 hexdouble OldEnvironment; 352 FEGETENVD( OldEnvironment.d ); 353 OldEnvironment.i.lo |= FE_UNDERFLOW; 354 FESETENVD( OldEnvironment.d ); 355 } 356 return result; 357 } 358 if ( y >= _HUGE ) 359 { 360 result = InvSqrtPI / y; 361 return result; 362 } 363 } 364 ysquared = 1.0 / ( y * y ); 365 numerator = p[5] * ysquared; 366 denominator = ysquared; 367 for ( i = 0; i < 4; i++ ) 368 { 369 numerator = ( numerator + p[i] ) * ysquared; 370 denominator = ( denominator + q[i] ) * ysquared; 371 } 372 result = ysquared * ( numerator + p[4] ) / ( denominator + q[4] ); 373 result = ( InvSqrtPI - result ) / y; 374 ysquared = trunc ( y * 16.0 ) / 16.0; 375 del = ( y - ysquared ) * ( y + ysquared ); 376 result = exp ( - ysquared * ysquared ) * exp ( - del ) * result; 377 } 378 379/******************************************************************************* 380* if the calling function is erf instead of erfc, take care of the * 381* underserved underflow. otherwise, the computation will produce the * 382* exception for erfc. * 383*******************************************************************************/ 384 385 if ( which == 0 ) 386 { 387 hexdouble OldEnvironment; 388 FEGETENVD( OldEnvironment.d ); 389 OldEnvironment.i.lo &= ~FE_UNDERFLOW; 390 FESETENVD( OldEnvironment.d ); 391 } 392 393 return ( which ) ? result : ( 0.5 - result ) + 0.5; 394 }