time-to-botec

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

kernel_rempio2.js (8937B)


      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 * ## Notice
     20 *
     21 * The following copyright and license were part of the original implementation available as part of [FreeBSD]{@link https://svnweb.freebsd.org/base/release/9.3.0/lib/msun/src/k_rem_pio2.c}. The implementation follows the original, but has been modified for JavaScript.
     22 *
     23 * ```text
     24 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
     25 *
     26 * Developed at SunPro, a Sun Microsystems, Inc. business.
     27 * Permission to use, copy, modify, and distribute this
     28 * software is freely granted, provided that this notice
     29 * is preserved.
     30 * ```
     31 */
     32 
     33 /* eslint-disable array-element-newline */
     34 
     35 'use strict';
     36 
     37 // MODULES //
     38 
     39 var floor = require( './../../../../base/special/floor' );
     40 var ldexp = require( './../../../../base/special/ldexp' );
     41 
     42 
     43 // VARIABLES //
     44 
     45 /*
     46 * Table of constants for `2/π` (`396` hex digits, `476` decimal).
     47 *
     48 * Integer array which contains the (`24*i`)-th to (`24*i+23`)-th bit of `2/π` after binary point. The corresponding floating value is
     49 *
     50 * ```tex
     51 * \operatorname{ipio2}[i] \cdot 2^{-24(i+1)}
     52 * ```
     53 *
     54 * This table must have at least `(e0-3)/24 + jk` terms. For quad precision (`e0 <= 16360`, `jk = 6`), this is `686`.
     55 */
     56 var IPIO2 = [
     57 	0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
     58 	0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
     59 	0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
     60 	0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
     61 	0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
     62 	0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
     63 	0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
     64 	0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
     65 	0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
     66 	0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
     67 	0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B
     68 ];
     69 
     70 // Double precision array, obtained by cutting `π/2` into `24` bits chunks...
     71 var PIO2 = [
     72 	1.57079625129699707031e+00, // 0x3FF921FB, 0x40000000
     73 	7.54978941586159635335e-08, // 0x3E74442D, 0x00000000
     74 	5.39030252995776476554e-15, // 0x3CF84698, 0x80000000
     75 	3.28200341580791294123e-22, // 0x3B78CC51, 0x60000000
     76 	1.27065575308067607349e-29, // 0x39F01B83, 0x80000000
     77 	1.22933308981111328932e-36, // 0x387A2520, 0x40000000
     78 	2.73370053816464559624e-44, // 0x36E38222, 0x80000000
     79 	2.16741683877804819444e-51  // 0x3569F31D, 0x00000000
     80 ];
     81 var TWO24 = 1.67772160000000000000e+07;  // 0x41700000, 0x00000000
     82 var TWON24 = 5.96046447753906250000e-08; // 0x3E700000, 0x00000000
     83 
     84 // Arrays for storing temporary values (note that, in C, this is not thread safe):
     85 var F = zeros( 20 );
     86 var Q = zeros( 20 );
     87 var FQ = zeros( 20 );
     88 var IQ = zeros( 20 );
     89 
     90 
     91 // FUNCTIONS //
     92 
     93 /**
     94 * Returns an array of zeros.
     95 *
     96 * @private
     97 * @param {NonNegativeInteger} len - array length
     98 * @returns {NonNegativeIntegerArray} output array
     99 */
    100 function zeros( len ) {
    101 	var out;
    102 	var i;
    103 
    104 	out = [];
    105 	for ( i = 0; i < len; i++ ) {
    106 		out.push( 0.0 );
    107 	}
    108 	return out;
    109 }
    110 
    111 /**
    112 * Performs the computation for `kernelRempio2()`.
    113 *
    114 * @private
    115 * @param {PositiveNumber} x - input value
    116 * @param {(Array|TypedArray|Object)} y - output object for storing double precision numbers
    117 * @param {integer} jz - number of terms of `ipio2[]` used
    118 * @param {Array<integer>} q - array with integral values, representing the 24-bits chunk of the product of `x` and `2/π`
    119 * @param {integer} q0 - the corresponding exponent of `q[0]` (the exponent for `q[i]` would be `q0-24*i`)
    120 * @param {integer} jk - `jk+1` is the initial number of terms of `IPIO2[]` needed in the computation
    121 * @param {integer} jv - index for pointing to the suitable `ipio2[]` for the computation
    122 * @param {integer} jx - `nx - 1`
    123 * @param {Array<number>} f - `IPIO2[]` in floating point
    124 * @returns {number} last three binary digits of `N`
    125 */
    126 function compute( x, y, jz, q, q0, jk, jv, jx, f ) {
    127 	var carry;
    128 	var fw;
    129 	var ih;
    130 	var jp;
    131 	var i;
    132 	var k;
    133 	var n;
    134 	var j;
    135 	var z;
    136 
    137 	// `jp+1` is the number of terms in `PIO2[]` needed:
    138 	jp = jk;
    139 
    140 	// Distill `q[]` into `IQ[]` in reverse order...
    141 	z = q[ jz ];
    142 	j = jz;
    143 	for ( i = 0; j > 0; i++ ) {
    144 		fw = ( TWON24 * z )|0;
    145 		IQ[ i ] = ( z - (TWO24*fw) )|0;
    146 		z = q[ j-1 ] + fw;
    147 		j -= 1;
    148 	}
    149 	// Compute `n`...
    150 	z = ldexp( z, q0 );
    151 	z -= 8.0 * floor( z*0.125 ); // Trim off integer >= 8
    152 	n = z|0;
    153 	z -= n;
    154 	ih = 0;
    155 	if ( q0 > 0 ) {
    156 		// Need `IQ[jz-1]` to determine `n`...
    157 		i = ( IQ[ jz-1 ] >> (24-q0) );
    158 		n += i;
    159 		IQ[ jz-1 ] -= ( i << (24-q0) );
    160 		ih = ( IQ[ jz-1 ] >> (23-q0) );
    161 	}
    162 	else if ( q0 === 0 ) {
    163 		ih = ( IQ[ jz-1 ] >> 23 );
    164 	}
    165 	else if ( z >= 0.5 ) {
    166 		ih = 2;
    167 	}
    168 	// Case: q > 0.5
    169 	if ( ih > 0 ) {
    170 		n += 1;
    171 		carry = 0;
    172 
    173 		// Compute `1-q`:
    174 		for ( i = 0; i < jz; i++ ) {
    175 			j = IQ[ i ];
    176 			if ( carry === 0 ) {
    177 				if ( j !== 0 ) {
    178 					carry = 1;
    179 					IQ[ i ] = 0x1000000 - j;
    180 				}
    181 			} else {
    182 				IQ[ i ] = 0xffffff - j;
    183 			}
    184 		}
    185 		if ( q0 > 0 ) {
    186 			// Rare case: chance is 1 in 12...
    187 			switch ( q0 ) { // eslint-disable-line default-case
    188 			case 1:
    189 				IQ[ jz-1 ] &= 0x7fffff;
    190 				break;
    191 			case 2:
    192 				IQ[ jz-1 ] &= 0x3fffff;
    193 				break;
    194 			}
    195 		}
    196 		if ( ih === 2 ) {
    197 			z = 1.0 - z;
    198 			if ( carry !== 0 ) {
    199 				z -= ldexp( 1.0, q0 );
    200 			}
    201 		}
    202 	}
    203 	// Check if re-computation is needed...
    204 	if ( z === 0.0 ) {
    205 		j = 0;
    206 		for ( i = jz-1; i >= jk; i-- ) {
    207 			j |= IQ[ i ];
    208 		}
    209 		if ( j === 0 ) {
    210 			// Need re-computation...
    211 			for ( k = 1; IQ[ jk-k ] === 0; k++ ) {
    212 				// `k` is the number of terms needed...
    213 			}
    214 			for ( i = jz+1; i <= jz+k; i++ ) {
    215 				// Add `q[jz+1]` to `q[jz+k]`...
    216 				f[ jx+i ] = IPIO2[ jv+i ];
    217 				fw = 0.0;
    218 				for ( j = 0; j <= jx; j++ ) {
    219 					fw += x[ j ] * f[ jx + (i-j) ];
    220 				}
    221 				q[ i ] = fw;
    222 			}
    223 			jz += k;
    224 			return compute( x, y, jz, q, q0, jk, jv, jx, f );
    225 		}
    226 	}
    227 	// Chop off zero terms...
    228 	if ( z === 0.0 ) {
    229 		jz -= 1;
    230 		q0 -= 24;
    231 		while ( IQ[ jz ] === 0 ) {
    232 			jz -= 1;
    233 			q0 -= 24;
    234 		}
    235 	} else {
    236 		// Break `z` into 24-bit if necessary...
    237 		z = ldexp( z, -q0 );
    238 		if ( z >= TWO24 ) {
    239 			fw = (TWON24*z)|0;
    240 			IQ[ jz ] = ( z - (TWO24*fw) )|0;
    241 			jz += 1;
    242 			q0 += 24;
    243 			IQ[ jz ] = fw;
    244 		} else {
    245 			IQ[ jz ] = z|0;
    246 		}
    247 	}
    248 	// Convert integer "bit" chunk to floating-point value...
    249 	fw = ldexp( 1.0, q0 );
    250 	for ( i = jz; i >= 0; i-- ) {
    251 		q[ i ] = fw * IQ[i];
    252 		fw *= TWON24;
    253 	}
    254 	// Compute `PIO2[0,...,jp]*q[jz,...,0]`...
    255 	for ( i = jz; i >= 0; i-- ) {
    256 		fw = 0.0;
    257 		for ( k = 0; k <= jp && k <= jz-i; k++ ) {
    258 			fw += PIO2[ k ] * q[ i+k ];
    259 		}
    260 		FQ[ jz-i ] = fw;
    261 	}
    262 	// Compress `FQ[]` into `y[]`...
    263 	fw = 0.0;
    264 	for ( i = jz; i >= 0; i-- ) {
    265 		fw += FQ[ i ];
    266 	}
    267 	if ( ih === 0 ) {
    268 		y[ 0 ] = fw;
    269 	} else {
    270 		y[ 0 ] = -fw;
    271 	}
    272 	fw = FQ[ 0 ] - fw;
    273 	for ( i = 1; i <= jz; i++ ) {
    274 		fw += FQ[i];
    275 	}
    276 	if ( ih === 0 ) {
    277 		y[ 1 ] = fw;
    278 	} else {
    279 		y[ 1 ] = -fw;
    280 	}
    281 	return ( n & 7 );
    282 }
    283 
    284 
    285 // MAIN //
    286 
    287 /**
    288 * Returns the last three binary digits of `N` with `y = x - Nπ/2` so that `|y| < π/2`.
    289 *
    290 * ## Method
    291 *
    292 * -   The method is to compute the integer (`mod 8`) and fraction parts of `2x/π` without doing the full multiplication. In general, we skip the part of the product that is known to be a huge integer (more accurately, equals `0 mod 8` ). Thus, the number of operations is independent of the exponent of the input.
    293 *
    294 * @private
    295 * @param {PositiveNumber} x - input value
    296 * @param {(Array|TypedArray|Object)} y - remainder elements
    297 * @param {PositiveInteger} e0 - the exponent of `x[0]` (must be <= 16360)
    298 * @param {PositiveInteger} nx - dimension of `x[]`
    299 * @returns {number} last three binary digits of `N`
    300 */
    301 function kernelRempio2( x, y, e0, nx ) {
    302 	var fw;
    303 	var jk;
    304 	var jv;
    305 	var jx;
    306 	var jz;
    307 	var q0;
    308 	var i;
    309 	var j;
    310 	var m;
    311 
    312 	// Initialize `jk` for double-precision floating-point numbers:
    313 	jk = 4;
    314 
    315 	// Determine `jx`, `jv`, `q0` (note that `q0 < 3`):
    316 	jx = nx - 1;
    317 	jv = ( (e0 - 3) / 24 )|0;
    318 	if ( jv < 0 ) {
    319 		jv = 0;
    320 	}
    321 	q0 = e0 - (24 * (jv + 1));
    322 
    323 	// Set up `F[0]` to `F[jx+jk]` where `F[jx+jk] = IPIO2[jv+jk]`:
    324 	j = jv - jx;
    325 	m = jx + jk;
    326 	for ( i = 0; i <= m; i++ ) {
    327 		if ( j < 0 ) {
    328 			F[ i ] = 0.0;
    329 		} else {
    330 			F[ i ] = IPIO2[ j ];
    331 		}
    332 		j += 1;
    333 	}
    334 	// Compute `Q[0],Q[1],...,Q[jk]`:
    335 	for ( i = 0; i <= jk; i++ ) {
    336 		fw = 0.0;
    337 		for ( j = 0; j <= jx; j++ ) {
    338 			fw += x[ j ] * F[ jx + (i-j) ];
    339 		}
    340 		Q[ i ] = fw;
    341 	}
    342 	jz = jk;
    343 	return compute( x, y, jz, Q, q0, jk, jv, jx, F );
    344 }
    345 
    346 
    347 // EXPORTS //
    348 
    349 module.exports = kernelRempio2;