time-to-botec

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

sincos.js (4241B)


      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 [k_sin.c]{@link https://svnweb.freebsd.org/base/release/9.3.0/lib/msun/src/k_sin.c} and [k_cos.c]{@link https://svnweb.freebsd.org/base/release/9.3.0/lib/msun/src/k_cos.c}. The implementation follows the original sine and cosine kernels, but has been modified for JavaScript and combined into a single function.
     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 'use strict';
     34 
     35 // MODULES //
     36 
     37 var getHighWord = require( '@stdlib/number/float64/base/get-high-word' );
     38 var rempio2 = require( './../../../../base/special/rempio2' );
     39 var kernelSincos = require( './kernel_sincos.js' );
     40 
     41 
     42 // VARIABLES //
     43 
     44 // Absolute value mask: 0x7fffffff = 2147483647 => 01111111111111111111111111111111
     45 var ABS_MASK = 0x7fffffff|0; // asm type annotation
     46 
     47 // Exponent mask: 0x7ff00000 = 2146435072 => 01111111111100000000000000000000
     48 var EXPONENT_MASK = 0x7ff00000|0; // asm type annotation
     49 
     50 // High word for PI/4: 0x3fe921fb = 1072243195 => 00111111111010010010000111111011
     51 var PIO4_HIGH_WORD = 0x3fe921fb|0; // asm type annotation
     52 
     53 // The smaller of the two cutoffs for the sine and cosine kernels: 2^-27 = 0x3e400000 => 00111110010000000000000000000000
     54 var SMALL_HIGH_WORD = 0x3e400000|0; // asm type annotation
     55 
     56 // Array for storing remainder elements:
     57 var Y = [ 0.0, 0.0 ];
     58 
     59 
     60 // MAIN //
     61 
     62 /**
     63 * Simultaneously computes the sine and cosine of a number.
     64 *
     65 * ## Method
     66 *
     67 * -   Let \\(S\\), \\(C\\), and \\(T\\) denote the \\(\sin\\), \\(\cos\\) and \\(\tan\\), respectively, on \\(\[-\pi/4, +\pi/4\]\\).
     68 *
     69 * -   Reduce the argument \\(x\\) to \\(y1+y2 = x-k\pi/2\\) in \\(\[-\pi/4, +\pi/4\]\\), and let \\(n = k \mod 4\\).
     70 *
     71 * -   We have
     72 *
     73 *     | n | sin(x) | cos(x) | tan(x) |
     74 *     | - | ------ | ------ | ------ |
     75 *     | 0 |    S   |    C   |   T    |
     76 *     | 1 |    C   |   -S   |  -1/T  |
     77 *     | 2 |   -S   |   -C   |   T    |
     78 *     | 3 |   -C   |    S   |  -1/T  |
     79 *
     80 *
     81 * @private
     82 * @param {(Array|TypedArray|Object)} out - destination array
     83 * @param {number} x - input value (in radians)
     84 * @returns {(Array|TypedArray|Object)} sine and cosine
     85 *
     86 * @example
     87 * var v = sincos( [ 0.0, 0.0 ], 0.0 );
     88 * // returns [ ~0.0, ~1.0 ]
     89 *
     90 * @example
     91 * var v = sincos( [ 0.0, 0.0 ], 3.141592653589793/2.0 );
     92 * // returns [ ~1.0, ~0.0 ]
     93 *
     94 * @example
     95 * var v = sincos( [ 0.0, 0.0 ], -3.141592653589793/6.0 );
     96 * // returns [ ~-0.5, ~0.866 ]
     97 *
     98 * @example
     99 * var v = sincos( [ 0.0, 0.0 ], NaN );
    100 * // returns [ NaN, NaN ]
    101 */
    102 function sincos( out, x ) {
    103 	var ix;
    104 	var n;
    105 
    106 	ix = getHighWord( x );
    107 
    108 	// Case: |x| ~< π/4
    109 	ix &= ABS_MASK;
    110 	if ( ix <= PIO4_HIGH_WORD ) {
    111 		// Case: |x| ~< 2^-26
    112 		if ( ix < SMALL_HIGH_WORD ) {
    113 			if ( (x|0) === 0 ) {
    114 				out[ 0 ] = x;
    115 				out[ 1 ] = 0.0;
    116 			}
    117 		}
    118 		return kernelSincos( out, x, 0.0 );
    119 	}
    120 	// Case: x is NaN or infinity
    121 	if ( ix >= EXPONENT_MASK ) {
    122 		out[ 0 ] = NaN;
    123 		out[ 1 ] = NaN;
    124 		return out;
    125 	}
    126 	// Argument reduction...
    127 	n = rempio2( x, Y );
    128 
    129 	// Compute the sine and cosine together:
    130 	kernelSincos( out, Y[ 0 ], Y[ 1 ] );
    131 
    132 	switch ( n & 3 ) {
    133 	case 1:
    134 		ix = out[ 1 ];
    135 		out[ 1 ] = -out[ 0 ];
    136 		out[ 0 ] = ix;
    137 		return out;
    138 	case 2:
    139 		out[ 0 ] *= -1;
    140 		out[ 1 ] *= -1;
    141 		return out;
    142 	case 3:
    143 		// Passing
    144 		ix = -out[ 1 ];
    145 		out[ 1 ] = out[ 0 ];
    146 		out[ 0 ] = ix;
    147 		return out;
    148 	default:
    149 		return out;
    150 	}
    151 }
    152 
    153 
    154 // EXPORTS //
    155 
    156 module.exports = sincos;