All files / expm1rel/lib main.js

83.51% Statements 76/91
100% Branches 1/1
0% Functions 0/1
83.51% Lines 76/91

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 921x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x                               1x 1x 1x 1x 1x  
/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
 
'use strict';
 
// MODULES //
 
var expm1 = require( '@stdlib/math/base/special/expm1' );
var abs = require( '@stdlib/math/base/special/abs' );
var EPS = require( '@stdlib/constants/float64/eps' );
var PINF = require( '@stdlib/constants/float64/pinf' );
 
 
// VARIABLES //
 
var HUGE_VALUE = 7.09782712893383973096e+02; // 0x40862E42 0xFEFA39EF
var OVERFLOW_THRESHOLD = 7.163568913878179e+02;
 
 
// MAIN //
 
/**
* Computes the relative error exponential.
*
* ## Method
*
* To avoid overflow when \\( x \\) exceeds the natural logarithm of the maximum double-precision floating-point number, we can derive the following identity:
*
* ```tex
* \begin{align*}
* \frac{e^x - 1}{x} &= \frac{(e^{x/2} - 1)(e^{x/2} + 1)}{x} \\
*                   &= \frac{(e^{x/2} - 1)(e^{x/2} - 1 + 2)}{x} \\
*                   &= \frac{\operatorname{expm1}(x/2) \cdot (\operatorname{expm1}(x/2) + 2)}{x} \\
*                   &= \frac{\operatorname{expm1}(x/2)}{x} \cdot (\operatorname{expm1}(x/2) + 2)
* \end{align*}
* ```
*
* @param {number} x - input value
* @returns {number} function value
*
* @example
* var v = expm1rel( 0.0 );
* // returns 1.0
*
* @example
* var v = expm1rel( 1.0 );
* // returns ~1.718
*
* @example
* var v = expm1rel( -1.0 );
* // returns ~0.632
*
* @example
* var v = expm1rel( NaN );
* // returns NaN
*/
function expm1rel( x ) {
	var tmp;
	if ( abs( x ) <= EPS ) {
		return 1.0; // L'Hopital's Rule
	}
	if ( x < HUGE_VALUE ) {
		return expm1( x ) / x;
	}
	if ( x >= OVERFLOW_THRESHOLD ) {
		return PINF; // L'Hopital's Rule
	}
	// HUGE_VALUE <= x < OVERFLOW_THRESHOLD
	tmp = expm1( x/2.0 );
	return ( tmp/x ) * ( tmp+2.0 ); // note: we keep the `+2` term in order to prevent compiler optimizations from rearranging terms, even though `tmp + 2 = tmp` due to the limits of floating-point precision
}
 
 
// EXPORTS //
 
module.exports = expm1rel;