time-to-botec

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

ldexp.js (3989B)


      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 'use strict';
     20 
     21 // NOTES //
     22 
     23 /*
     24 * => ldexp: load exponent (see [The Open Group]{@link http://pubs.opengroup.org/onlinepubs/9699919799/functions/ldexp.html} and [cppreference]{@link http://en.cppreference.com/w/c/numeric/math/ldexp}).
     25 */
     26 
     27 
     28 // MODULES //
     29 
     30 var PINF = require( '@stdlib/constants/float64/pinf' );
     31 var NINF = require( '@stdlib/constants/float64/ninf' );
     32 var BIAS = require( '@stdlib/constants/float64/exponent-bias' );
     33 var MAX_EXPONENT = require( '@stdlib/constants/float64/max-base2-exponent' );
     34 var MAX_SUBNORMAL_EXPONENT = require( '@stdlib/constants/float64/max-base2-exponent-subnormal' );
     35 var MIN_SUBNORMAL_EXPONENT = require( '@stdlib/constants/float64/min-base2-exponent-subnormal' );
     36 var isnan = require( './../../../../base/assert/is-nan' );
     37 var isInfinite = require( './../../../../base/assert/is-infinite' );
     38 var copysign = require( './../../../../base/special/copysign' );
     39 var normalize = require( '@stdlib/number/float64/base/normalize' );
     40 var floatExp = require( '@stdlib/number/float64/base/exponent' );
     41 var toWords = require( '@stdlib/number/float64/base/to-words' );
     42 var fromWords = require( '@stdlib/number/float64/base/from-words' );
     43 
     44 
     45 // VARIABLES //
     46 
     47 // 1/(1<<52) = 1/(2**52) = 1/4503599627370496
     48 var TWO52_INV = 2.220446049250313e-16;
     49 
     50 // Exponent all 0s: 1 00000000000 11111111111111111111 => 2148532223
     51 var CLEAR_EXP_MASK = 0x800fffff>>>0; // asm type annotation
     52 
     53 // Normalization workspace:
     54 var FRAC = [ 0.0, 0.0 ]; // WARNING: not thread safe
     55 
     56 // High/low words workspace:
     57 var WORDS = [ 0, 0 ]; // WARNING: not thread safe
     58 
     59 
     60 // MAIN //
     61 
     62 /**
     63 * Multiplies a double-precision floating-point number by an integer power of two.
     64 *
     65 * @param {number} frac - fraction
     66 * @param {integer} exp - exponent
     67 * @returns {number} double-precision floating-point number
     68 *
     69 * @example
     70 * var x = ldexp( 0.5, 3 ); // => 0.5 * 2^3 = 0.5 * 8
     71 * // returns 4.0
     72 *
     73 * @example
     74 * var x = ldexp( 4.0, -2 ); // => 4 * 2^(-2) = 4 * (1/4)
     75 * // returns 1.0
     76 *
     77 * @example
     78 * var x = ldexp( 0.0, 20 );
     79 * // returns 0.0
     80 *
     81 * @example
     82 * var x = ldexp( -0.0, 39 );
     83 * // returns -0.0
     84 *
     85 * @example
     86 * var x = ldexp( NaN, -101 );
     87 * // returns NaN
     88 *
     89 * @example
     90 * var x = ldexp( Infinity, 11 );
     91 * // returns Infinity
     92 *
     93 * @example
     94 * var x = ldexp( -Infinity, -118 );
     95 * // returns -Infinity
     96 */
     97 function ldexp( frac, exp ) {
     98 	var high;
     99 	var m;
    100 	if (
    101 		frac === 0.0 || // handles +-0
    102 		isnan( frac ) ||
    103 		isInfinite( frac )
    104 	) {
    105 		return frac;
    106 	}
    107 	// Normalize the input fraction:
    108 	normalize( FRAC, frac );
    109 	frac = FRAC[ 0 ];
    110 	exp += FRAC[ 1 ];
    111 
    112 	// Extract the exponent from `frac` and add it to `exp`:
    113 	exp += floatExp( frac );
    114 
    115 	// Check for underflow/overflow...
    116 	if ( exp < MIN_SUBNORMAL_EXPONENT ) {
    117 		return copysign( 0.0, frac );
    118 	}
    119 	if ( exp > MAX_EXPONENT ) {
    120 		if ( frac < 0.0 ) {
    121 			return NINF;
    122 		}
    123 		return PINF;
    124 	}
    125 	// Check for a subnormal and scale accordingly to retain precision...
    126 	if ( exp <= MAX_SUBNORMAL_EXPONENT ) {
    127 		exp += 52;
    128 		m = TWO52_INV;
    129 	} else {
    130 		m = 1.0;
    131 	}
    132 	// Split the fraction into higher and lower order words:
    133 	toWords( WORDS, frac );
    134 	high = WORDS[ 0 ];
    135 
    136 	// Clear the exponent bits within the higher order word:
    137 	high &= CLEAR_EXP_MASK;
    138 
    139 	// Set the exponent bits to the new exponent:
    140 	high |= ((exp+BIAS) << 20);
    141 
    142 	// Create a new floating-point number:
    143 	return m * fromWords( high, WORDS[ 1 ] );
    144 }
    145 
    146 
    147 // EXPORTS //
    148 
    149 module.exports = ldexp;