time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

marsaglia.js (3807B)


      1 /**
      2 * @license Apache-2.0
      3 *
      4 * Copyright (c) 2018 The Stdlib Authors.
      5 *
      6 * Licensed under the Apache License, Version 2.0 (the "License");
      7 * you may not use this file except in compliance with the License.
      8 * You may obtain a copy of the License at
      9 *
     10 *    http://www.apache.org/licenses/LICENSE-2.0
     11 *
     12 * Unless required by applicable law or agreed to in writing, software
     13 * distributed under the License is distributed on an "AS IS" BASIS,
     14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15 * See the License for the specific language governing permissions and
     16 * limitations under the License.
     17 */
     18 
     19 'use strict';
     20 
     21 // MODULES //
     22 
     23 var floor = require( '@stdlib/math/base/special/floor' );
     24 var sqrt = require( '@stdlib/math/base/special/sqrt' );
     25 var pow = require( '@stdlib/math/base/special/pow' );
     26 var exp = require( '@stdlib/math/base/special/exp' );
     27 var Float64Array = require( '@stdlib/array/float64' );
     28 
     29 
     30 // MAIN //
     31 
     32 /**
     33 * Evaluates the Kolmogorov distribution. This function is a JavaScript implementation of a procedure developed by Marsaglia & Tsang.
     34 *
     35 * ## References
     36 *
     37 * -   Marsaglia, George, Wai Wan Tsang, and Jingbo Wang. 2003. "Evaluating Kolmogorov's Distribution." _Journal of Statistical Software_ 8 (18): 1–4. doi:[10.18637/jss.v008.i18](https://doi.org/10.18637/jss.v008.i18).
     38 *
     39 * @private
     40 * @param {number} d - the argument of the CDF of D_n
     41 * @param {number} n - number of variates
     42 * @returns {number} evaluated CDF, i.e. P( D_n < d )
     43 */
     44 function pKolmogorov( d, n ) {
     45 	var eH;
     46 	var eQ;
     47 	var h;
     48 	var H;
     49 	var Q;
     50 	var g;
     51 	var i;
     52 	var j;
     53 	var k;
     54 	var m;
     55 	var s;
     56 
     57 	s = d * d * n;
     58 	if ( s > 7.24 || ( s > 3.76 && n > 99 ) ) {
     59 		return 1 - (2 * exp( -( 2.000071 + (0.331/sqrt(n)) + (1.409/n) ) * s ));
     60 	}
     61 	k = floor( n * d ) + 1;
     62 	m = (2*k) - 1;
     63 	h = k - (n*d);
     64 	H = new Float64Array( m * m );
     65 	Q = new Float64Array( m * m );
     66 	for ( i = 0; i < m; i++ ) {
     67 		for ( j = 0; j < m; j++ ) {
     68 			if ( i - j + 1 < 0 ) {
     69 				H[ (i*m) + j ] = 0;
     70 			} else {
     71 				H[ (i*m) + j ] = 1;
     72 			}
     73 		}
     74 	}
     75 	for ( i = 0; i < m; i++ ) {
     76 		H[ i * m ] -= pow( h, i+1 );
     77 		H[ ((m-1) * m) + i ] -= pow( h, (m-i) );
     78 	}
     79 	H[ (m-1) * m ] += ( ( (2*h)-1 > 0 ) ? pow( (2*h)-1, m ) : 0 );
     80 	for ( i = 0; i < m; i++ ) {
     81 		for ( j = 0; j < m; j++ ) {
     82 			if ( i - j + 1 > 0 ) {
     83 				for ( g = 1; g <= i - j + 1; g++ ) {
     84 					H[ (i*m) + j ] /= g;
     85 				}
     86 			}
     87 		}
     88 	}
     89 	eH = 0;
     90 	mpow( H, eH, n );
     91 	s = Q[ ((k-1) * m) + k - 1 ];
     92 	for ( i = 1; i <= n; i++ ) {
     93 		s = s * i / n;
     94 		if ( s < 1e-140 ) {
     95 			s *= 1e140;
     96 			eQ -= 140;
     97 		}
     98 	}
     99 	s *= pow( 10, eQ );
    100 	return s;
    101 
    102 	/**
    103 	* Matrix exponentiation. Mutates Q matrix.
    104 	*
    105 	* @private
    106 	* @param {Float64Array} A - input matrix
    107 	* @param {number} eA - matrix power
    108 	* @param {number} n - number of variates
    109 	*/
    110 	function mpow( A, eA, n ) {
    111 		var eB;
    112 		var B;
    113 		var i;
    114 
    115 		if ( n === 1 ) {
    116 			for ( i = 0; i < m*m; i++ ) {
    117 				Q[ i ] = A[ i ];
    118 				eQ = eA;
    119 			}
    120 			return;
    121 		}
    122 		mpow( A, eA, floor( n/2 ) );
    123 		B = mmult( Q, Q );
    124 		eB = 2 * eQ;
    125 		if ( n % 2 === 0 ) {
    126 			for ( i = 0; i < m*m; i++ ) {
    127 				Q[ i ] = B[ i ];
    128 			}
    129 			eQ = eB;
    130 		} else {
    131 			Q = mmult( A, B );
    132 			eQ = eA + eB;
    133 		}
    134 		if ( Q[ (floor(m/2) * m) + floor(m/2) ] > 1e140 ) {
    135 			for ( i = 0; i < m*m; i++ ) {
    136 				Q[ i ] *= 1e-140;
    137 			}
    138 			eQ += 140;
    139 		}
    140 	}
    141 
    142 	/**
    143 	* Multiply matrices x and y.
    144 	*
    145 	* @private
    146 	* @param {Float64Array} x - first input matrix
    147 	* @param {Float64Array} y - second input matrix
    148 	* @returns {Float64Array} matrix product
    149 	*/
    150 	function mmult( x, y ) {
    151 		var i;
    152 		var j;
    153 		var k;
    154 		var s;
    155 		var z;
    156 
    157 		z = new Float64Array( m * m );
    158 		for ( i = 0; i < m; i++) {
    159 			for ( j = 0; j < m; j++ ) {
    160 				s = 0;
    161 				for ( k = 0; k < m; k++ ) {
    162 					s += x[ (i*m) + k ] * y[ (k*m) + j ];
    163 					z[ (i*m) + j ] = s;
    164 				}
    165 			}
    166 		}
    167 		return z;
    168 	}
    169 }
    170 
    171 
    172 // EXPORTS //
    173 
    174 module.exports = pKolmogorov;