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;