time-to-botec

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

y0.js (4236B)


      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 original C++ code and copyright notice are from the [Boost library]{@link https://github.com/boostorg/math/blob/develop/include/boost/math/special_functions/detail/bessel_y0.hpp}. The implementation has been modified for JavaScript.
     22 *
     23 * ```text
     24 * Copyright Xiaogang Zhang, 2006.
     25 *
     26 * Use, modification and distribution are subject to the
     27 * Boost Software License, Version 1.0. (See accompanying file
     28 * LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
     29 * ```
     30 */
     31 
     32 'use strict';
     33 
     34 // MODULES //
     35 
     36 var ln = require( './../../../../base/special/ln' );
     37 var sqrt = require( './../../../../base/special/sqrt' );
     38 var PI = require( '@stdlib/constants/float64/pi' );
     39 var SQRT_PI = require( '@stdlib/constants/float64/sqrt-pi' );
     40 var NINF = require( '@stdlib/constants/float64/ninf' );
     41 var PINF = require( '@stdlib/constants/float64/pinf' );
     42 var sincos = require( './../../../../base/special/sincos' );
     43 var besselj0 = require( './../../../../base/special/besselj0' );
     44 var poly1 = require( './rational_p1q1.js' );
     45 var poly2 = require( './rational_p2q2.js' );
     46 var poly3 = require( './rational_p3q3.js' );
     47 var polyC = require( './rational_pcqc.js' );
     48 var polyS = require( './rational_psqs.js' );
     49 
     50 
     51 // VARIABLES //
     52 
     53 var ONE_DIV_SQRT_PI = 1.0 / SQRT_PI;
     54 var TWO_DIV_PI = 2.0 / PI;
     55 
     56 var x1 = 8.9357696627916752158e-01;
     57 var x2 = 3.9576784193148578684e+00;
     58 var x3 = 7.0860510603017726976e+00;
     59 var x11 = 2.280e+02;
     60 var x12 = 2.9519662791675215849e-03;
     61 var x21 = 1.0130e+03;
     62 var x22 = 6.4716931485786837568e-04;
     63 var x31 = 1.8140e+03;
     64 var x32 = 1.1356030177269762362e-04;
     65 
     66 // `sincos` workspace:
     67 var sc = [ 0.0, 0.0 ]; // WARNING: not thread safe
     68 
     69 
     70 // MAIN //
     71 
     72 /**
     73 * Computes the Bessel function of the second kind of order zero.
     74 *
     75 * ## Notes
     76 *
     77 * -   Accuracy for subnormal `x` is very poor. Full accuracy is achieved at `1.0e-308` but trends progressively to zero at `5e-324`. This suggests that underflow (or overflow, perhaps due to a reciprocal) is effectively cutting off digits of precision until the computation loses all accuracy at `5e-324`.
     78 *
     79 * @param {number} x - input value
     80 * @returns {number} evaluated Bessel function
     81 *
     82 * @example
     83 * var v = y0( 0.0 );
     84 * // returns -Infinity
     85 *
     86 * v = y0( 1.0 );
     87 * // returns ~0.088
     88 *
     89 * v = y0( -1.0 );
     90 * // returns NaN
     91 *
     92 * v = y0( Infinity );
     93 * // returns 0.0
     94 *
     95 * v = y0( -Infinity );
     96 * // returns NaN
     97 *
     98 * v = y0( NaN );
     99 * // returns NaN
    100 */
    101 function y0( x ) {
    102 	var rc;
    103 	var rs;
    104 	var y2;
    105 	var r;
    106 	var y;
    107 	var z;
    108 	var f;
    109 
    110 	if ( x < 0.0 ) {
    111 		return NaN;
    112 	}
    113 	if ( x === 0.0 ) {
    114 		return NINF;
    115 	}
    116 	if ( x === PINF ) {
    117 		return 0.0;
    118 	}
    119 	if ( x <= 3.0 ) {
    120 		y = x * x;
    121 		z = ( ln( x/x1 ) * besselj0( x ) ) * TWO_DIV_PI;
    122 		r = poly1( y );
    123 		f = ( x+x1 ) * ( ( x - (x11/256.0) ) - x12 );
    124 		return z + ( f*r );
    125 	}
    126 	if ( x <= 5.5 ) {
    127 		y = x * x;
    128 		z = ( ln( x/x2 ) * besselj0( x ) ) * TWO_DIV_PI;
    129 		r = poly2( y );
    130 		f = ( x+x2 ) * ( (x - (x21/256.0)) - x22 );
    131 		return z + ( f*r );
    132 	}
    133 	if ( x <= 8.0 ) {
    134 		y = x * x;
    135 		z = ( ln( x/x3 ) * besselj0( x ) ) * TWO_DIV_PI;
    136 		r = poly3( y );
    137 		f = ( x+x3 ) * ( (x - (x31/256.0)) - x32 );
    138 		return z + ( f*r );
    139 	}
    140 	y = 8.0 / x;
    141 	y2 = y * y;
    142 	rc = polyC( y2 );
    143 	rs = polyS( y2 );
    144 	f = ONE_DIV_SQRT_PI / sqrt( x );
    145 
    146 	/*
    147 	* The following code is really just:
    148 	*
    149 	* ```
    150 	* z = x - 0.25 * pi;
    151 	* value = f * ( rc * sin( z ) + y * rs * cos( z ) );
    152 	* ```
    153 	*
    154 	* But using the sin/cos addition formulae and constant values for sin/cos of `π/4` which then cancel part of the "f" term as they're all `1/sqrt(2)`:
    155 	*/
    156 	sincos( sc, x );
    157 	return f * ( ( rc * (sc[0]-sc[1]) ) + ( (y*rs) * (sc[1]+sc[0]) ) );
    158 }
    159 
    160 
    161 // EXPORTS //
    162 
    163 module.exports = y0;