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;