kerneltest/e32utils/nistsecurerng/src/cephes.cpp
changeset 152 657f875b013e
equal deleted inserted replaced
139:95f71bcdcdb7 152:657f875b013e
       
     1 /*
       
     2 * Portions Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 * The original NIST Statistical Test Suite code is placed in public domain.
       
    16 * (http://csrc.nist.gov/groups/ST/toolkit/rng/documentation_software.html) 
       
    17 * 
       
    18 * This software was developed at the National Institute of Standards and Technology by 
       
    19 * employees of the Federal Government in the course of their official duties. Pursuant
       
    20 * to title 17 Section 105 of the United States Code this software is not subject to 
       
    21 * copyright protection and is in the public domain. The NIST Statistical Test Suite is
       
    22 * an experimental system. NIST assumes no responsibility whatsoever for its use by other 
       
    23 * parties, and makes no guarantees, expressed or implied, about its quality, reliability, 
       
    24 * or any other characteristic. We would appreciate acknowledgment if the software is used.
       
    25 */
       
    26 
       
    27 
       
    28 
       
    29 #include "openc.h"
       
    30 #include "../include/cephes.h"
       
    31 
       
    32 static const double	rel_error = 1E-12;
       
    33 
       
    34 double MACHEP = 1.11022302462515654042E-16;		// 2**-53
       
    35 double MAXLOG = 7.09782712893383996732224E2;	// log(MAXNUM)
       
    36 double MAXNUM = 1.7976931348623158E308;			// 2**1024*(1-MACHEP)
       
    37 double PI     = 3.14159265358979323846;			// pi, duh!
       
    38 
       
    39 static double big = 4.503599627370496e15;
       
    40 static double biginv =  2.22044604925031308085e-16;
       
    41 
       
    42 int sgngam = 0;
       
    43 
       
    44 double
       
    45 cephes_igamc(double a, double x)
       
    46 {
       
    47 	double ans, ax, c, yc, r, t, y, z;
       
    48 	double pk, pkm1, pkm2, qk, qkm1, qkm2;
       
    49 
       
    50 	if ( (x <= 0) || ( a <= 0) )
       
    51 		return( 1.0 );
       
    52 
       
    53 	if ( (x < 1.0) || (x < a) )
       
    54 		return( 1.e0 - cephes_igam(a,x) );
       
    55 
       
    56 	ax = a * log(x) - x - cephes_lgam(a);
       
    57 
       
    58 	if ( ax < -MAXLOG ) {
       
    59 		printf("igamc: UNDERFLOW\n");
       
    60 		return 0.0;
       
    61 	}
       
    62 	ax = exp(ax);
       
    63 
       
    64 	/* continued fraction */
       
    65 	y = 1.0 - a;
       
    66 	z = x + y + 1.0;
       
    67 	c = 0.0;
       
    68 	pkm2 = 1.0;
       
    69 	qkm2 = x;
       
    70 	pkm1 = x + 1.0;
       
    71 	qkm1 = z * x;
       
    72 	ans = pkm1/qkm1;
       
    73 
       
    74 	do {
       
    75 		c += 1.0;
       
    76 		y += 1.0;
       
    77 		z += 2.0;
       
    78 		yc = y * c;
       
    79 		pk = pkm1 * z  -  pkm2 * yc;
       
    80 		qk = qkm1 * z  -  qkm2 * yc;
       
    81 		if ( qk != 0 ) {
       
    82 			r = pk/qk;
       
    83 			t = fabs( (ans - r)/r );
       
    84 			ans = r;
       
    85 		}
       
    86 		else
       
    87 			t = 1.0;
       
    88 		pkm2 = pkm1;
       
    89 		pkm1 = pk;
       
    90 		qkm2 = qkm1;
       
    91 		qkm1 = qk;
       
    92 		if ( fabs(pk) > big ) {
       
    93 			pkm2 *= biginv;
       
    94 			pkm1 *= biginv;
       
    95 			qkm2 *= biginv;
       
    96 			qkm1 *= biginv;
       
    97 		}
       
    98 	} while ( t > MACHEP );
       
    99 
       
   100 	return ans*ax;
       
   101 }
       
   102 
       
   103 double
       
   104 cephes_igam(double a, double x)
       
   105 {
       
   106 	double ans, ax, c, r;
       
   107 
       
   108 	if ( (x <= 0) || ( a <= 0) )
       
   109 		return 0.0;
       
   110 
       
   111 	if ( (x > 1.0) && (x > a ) )
       
   112 		return 1.e0 - cephes_igamc(a,x);
       
   113 
       
   114 	/* Compute  x**a * exp(-x) / gamma(a)  */
       
   115 	ax = a * log(x) - x - cephes_lgam(a);
       
   116 	if ( ax < -MAXLOG ) {
       
   117 		printf("igam: UNDERFLOW\n");
       
   118 		return 0.0;
       
   119 	}
       
   120 	ax = exp(ax);
       
   121 
       
   122 	/* power series */
       
   123 	r = a;
       
   124 	c = 1.0;
       
   125 	ans = 1.0;
       
   126 
       
   127 	do {
       
   128 		r += 1.0;
       
   129 		c *= x/r;
       
   130 		ans += c;
       
   131 	} while ( c/ans > MACHEP );
       
   132 
       
   133 	return ans * ax/a;
       
   134 }
       
   135 
       
   136 
       
   137 /* A[]: Stirling's formula expansion of log gamma
       
   138  * B[], C[]: log gamma function between 2 and 3
       
   139  */
       
   140 static unsigned short A[] = {
       
   141 	0x6661,0x2733,0x9850,0x3f4a,
       
   142 	0xe943,0xb580,0x7fbd,0xbf43,
       
   143 	0x5ebb,0x20dc,0x019f,0x3f4a,
       
   144 	0xa5a1,0x16b0,0xc16c,0xbf66,
       
   145 	0x554b,0x5555,0x5555,0x3fb5
       
   146 };
       
   147 static unsigned short B[] = {
       
   148 	0x6761,0x8ff3,0x8901,0xc095,
       
   149 	0xb93e,0x355b,0xf234,0xc0e2,
       
   150 	0x89e5,0xf890,0x3d73,0xc114,
       
   151 	0xdb51,0xf994,0xbc82,0xc131,
       
   152 	0xf20b,0x0219,0x4589,0xc13a,
       
   153 	0x055e,0x5418,0x0c67,0xc12a
       
   154 };
       
   155 static unsigned short C[] = {
       
   156 	/*0x0000,0x0000,0x0000,0x3ff0,*/
       
   157 	0x12b2,0x1cf3,0xfd0d,0xc075,
       
   158 	0xd757,0x7b89,0xaa0d,0xc0d0,
       
   159 	0x4c9b,0xb974,0xeb84,0xc10a,
       
   160 	0x0043,0x7195,0x6286,0xc131,
       
   161 	0xf34c,0x892f,0x5255,0xc143,
       
   162 	0xe14a,0x6a11,0xce4b,0xc13e
       
   163 };
       
   164 
       
   165 #define MAXLGM 2.556348e305
       
   166 
       
   167 
       
   168 /* Logarithm of gamma function */
       
   169 double
       
   170 cephes_lgam(double x)
       
   171 {
       
   172 	double	p, q, u, w, z;
       
   173 	int		i;
       
   174 
       
   175 	sgngam = 1;
       
   176 
       
   177 	if ( x < -34.0 ) {
       
   178 		q = -x;
       
   179 		w = cephes_lgam(q); /* note this modifies sgngam! */
       
   180 		p = floor(q);
       
   181 		if ( p == q ) {
       
   182 lgsing:
       
   183 			goto loverf;
       
   184 		}
       
   185 		i = (int)p;
       
   186 		if ( (i & 1) == 0 )
       
   187 			sgngam = -1;
       
   188 		else
       
   189 			sgngam = 1;
       
   190 		z = q - p;
       
   191 		if ( z > 0.5 ) {
       
   192 			p += 1.0;
       
   193 			z = p - q;
       
   194 		}
       
   195 		z = q * sin( PI * z );
       
   196 		if ( z == 0.0 )
       
   197 			goto lgsing;
       
   198 		/*      z = log(PI) - log( z ) - w;*/
       
   199 		z = log(PI) - log( z ) - w;
       
   200 		return z;
       
   201 	}
       
   202 
       
   203 	if ( x < 13.0 ) {
       
   204 		z = 1.0;
       
   205 		p = 0.0;
       
   206 		u = x;
       
   207 		while ( u >= 3.0 ) {
       
   208 			p -= 1.0;
       
   209 			u = x + p;
       
   210 			z *= u;
       
   211 		}
       
   212 		while ( u < 2.0 ) {
       
   213 			if ( u == 0.0 )
       
   214 				goto lgsing;
       
   215 			z /= u;
       
   216 			p += 1.0;
       
   217 			u = x + p;
       
   218 		}
       
   219 		if ( z < 0.0 ) {
       
   220 			sgngam = -1;
       
   221 			z = -z;
       
   222 		}
       
   223 		else
       
   224 			sgngam = 1;
       
   225 		if ( u == 2.0 )
       
   226 			return( log(z) );
       
   227 		p -= 2.0;
       
   228 		x = x + p;
       
   229 		p = x * cephes_polevl( x, (double *)B, 5 ) / cephes_p1evl( x, (double *)C, 6);
       
   230 
       
   231 		return log(z) + p;
       
   232 	}
       
   233 
       
   234 	if ( x > MAXLGM ) {
       
   235 loverf:
       
   236 		printf("lgam: OVERFLOW\n");
       
   237 
       
   238 		return sgngam * MAXNUM;
       
   239 	}
       
   240 
       
   241 	q = ( x - 0.5 ) * log(x) - x + log( sqrt( 2*PI ) );
       
   242 	if ( x > 1.0e8 )
       
   243 		return q;
       
   244 
       
   245 	p = 1.0/(x*x);
       
   246 	if ( x >= 1000.0 )
       
   247 		q += ((   7.9365079365079365079365e-4 * p
       
   248 		        - 2.7777777777777777777778e-3) *p
       
   249 				+ 0.0833333333333333333333) / x;
       
   250 	else
       
   251 		q += cephes_polevl( p, (double *)A, 4 ) / x;
       
   252 
       
   253 	return q;
       
   254 }
       
   255 
       
   256 double
       
   257 cephes_polevl(double x, double *coef, int N)
       
   258 {
       
   259 	double	ans;
       
   260 	int		i;
       
   261 	double	*p;
       
   262 
       
   263 	p = coef;
       
   264 	ans = *p++;
       
   265 	i = N;
       
   266 
       
   267 	do
       
   268 		ans = ans * x  +  *p++;
       
   269 	while ( --i );
       
   270 
       
   271 	return ans;
       
   272 }
       
   273 
       
   274 double
       
   275 cephes_p1evl(double x, double *coef, int N)
       
   276 {
       
   277 	double	ans;
       
   278 	double	*p;
       
   279 	int		i;
       
   280 
       
   281 	p = coef;
       
   282 	ans = x + *p++;
       
   283 	i = N-1;
       
   284 
       
   285 	do
       
   286 		ans = ans * x  + *p++;
       
   287 	while ( --i );
       
   288 
       
   289 	return ans;
       
   290 }
       
   291 
       
   292 double
       
   293 cephes_erf(double x)
       
   294 {
       
   295 	static const double two_sqrtpi = 1.128379167095512574;
       
   296 	double	sum = x, term = x, xsqr = x * x;
       
   297 	int		j = 1;
       
   298 
       
   299 	if ( fabs(x) > 2.2 )
       
   300 		return 1.0 - cephes_erfc(x);
       
   301 
       
   302 	do {
       
   303 		term *= xsqr/j;
       
   304 		sum -= term/(2*j+1);
       
   305 		j++;
       
   306 		term *= xsqr/j;
       
   307 		sum += term/(2*j+1);
       
   308 		j++;
       
   309 	} while ( fabs(term)/sum > rel_error );
       
   310 
       
   311 	return two_sqrtpi*sum;
       
   312 }
       
   313 
       
   314 double
       
   315 cephes_erfc(double x)
       
   316 {
       
   317 	static const double one_sqrtpi = 0.564189583547756287;
       
   318 	double	a = 1, b = x, c = x, d = x*x + 0.5;
       
   319 	double	q1, q2 = b/d, n = 1.0, t;
       
   320 
       
   321 	if ( fabs(x) < 2.2 )
       
   322 		return 1.0 - cephes_erf(x);
       
   323 	if ( x < 0 )
       
   324 		return 2.0 - cephes_erfc(-x);
       
   325 
       
   326 	do {
       
   327 		t = a*n + b*x;
       
   328 		a = b;
       
   329 		b = t;
       
   330 		t = c*n + d*x;
       
   331 		c = d;
       
   332 		d = t;
       
   333 		n += 0.5;
       
   334 		q1 = q2;
       
   335 		q2 = b/d;
       
   336 	} while ( fabs(q1-q2)/q2 > rel_error );
       
   337 
       
   338 	return one_sqrtpi*exp(-x*x)*q2;
       
   339 }
       
   340 
       
   341 
       
   342 double
       
   343 cephes_normal(double x)
       
   344 {
       
   345 	double arg, result, sqrt2=1.414213562373095048801688724209698078569672;
       
   346 
       
   347 	if (x > 0) {
       
   348 		arg = x/sqrt2;
       
   349 		result = 0.5 * ( 1 + erf(arg) );
       
   350 	}
       
   351 	else {
       
   352 		arg = -x/sqrt2;
       
   353 		result = 0.5 * ( 1 - erf(arg) );
       
   354 	}
       
   355 
       
   356 	return( result);
       
   357 }