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;