modf.js (3932B)
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 // MODULES // 22 23 var isnan = require( './../../../../base/assert/is-nan' ); 24 var toWords = require( '@stdlib/number/float64/base/to-words' ); 25 var fromWords = require( '@stdlib/number/float64/base/from-words' ); 26 var PINF = require( '@stdlib/constants/float64/pinf' ); 27 var FLOAT64_EXPONENT_BIAS = require( '@stdlib/constants/float64/exponent-bias' ); 28 var FLOAT64_HIGH_WORD_EXPONENT_MASK = require( '@stdlib/constants/float64/high-word-exponent-mask' ); // eslint-disable-line id-length 29 var FLOAT64_HIGH_WORD_SIGNIFICAND_MASK = require( '@stdlib/constants/float64/high-word-significand-mask' ); // eslint-disable-line id-length 30 31 32 // VARIABLES // 33 34 // 4294967295 => 0xffffffff => 11111111111111111111111111111111 35 var ALL_ONES = 4294967295>>>0; // asm type annotation 36 37 // High/low words workspace: 38 var WORDS = [ 0|0, 0|0 ]; // WARNING: not thread safe 39 40 41 // MAIN // 42 43 /** 44 * Decomposes a double-precision floating-point number into integral and fractional parts, each having the same type and sign as the input value. 45 * 46 * @private 47 * @param {(Array|TypedArray|Object)} out - output array 48 * @param {number} x - input value 49 * @returns {(Array|TypedArray|Object)} output array 50 * 51 * @example 52 * var parts = modf( [ 0.0, 0.0 ], 3.14 ); 53 * // returns [ 3.0, 0.14000000000000012 ] 54 */ 55 function modf( out, x ) { 56 var high; 57 var low; 58 var exp; 59 var i; 60 61 // Special cases... 62 if ( x < 1.0 ) { 63 if ( x < 0.0 ) { 64 modf( out, -x ); 65 out[ 0 ] *= -1.0; 66 out[ 1 ] *= -1.0; 67 return out; 68 } 69 if ( x === 0.0 ) { // [ +-0, +-0 ] 70 out[ 0 ] = x; 71 out[ 1 ] = x; 72 return out; 73 } 74 out[ 0 ] = 0.0; 75 out[ 1 ] = x; 76 return out; 77 } 78 if ( isnan( x ) ) { 79 out[ 0 ] = NaN; 80 out[ 1 ] = NaN; 81 return out; 82 } 83 if ( x === PINF ) { 84 out[ 0 ] = PINF; 85 out[ 1 ] = 0.0; 86 return out; 87 } 88 // Decompose |x|... 89 90 // Extract the high and low words: 91 toWords( WORDS, x ); 92 high = WORDS[ 0 ]; 93 low = WORDS[ 1 ]; 94 95 // Extract the unbiased exponent from the high word: 96 exp = ((high & FLOAT64_HIGH_WORD_EXPONENT_MASK) >> 20)|0; // asm type annotation 97 exp -= FLOAT64_EXPONENT_BIAS|0; // asm type annotation 98 99 // Handle smaller values (x < 2**20 = 1048576)... 100 if ( exp < 20 ) { 101 i = (FLOAT64_HIGH_WORD_SIGNIFICAND_MASK >> exp)|0; // asm type annotation 102 103 // Determine if `x` is integral by checking for significand bits which cannot be exponentiated away... 104 if ( ((high&i)|low) === 0 ) { 105 out[ 0 ] = x; 106 out[ 1 ] = 0.0; 107 return out; 108 } 109 // Turn off all the bits which cannot be exponentiated away: 110 high &= (~i); 111 112 // Generate the integral part: 113 i = fromWords( high, 0 ); 114 115 // The fractional part is whatever is leftover: 116 out[ 0 ] = i; 117 out[ 1 ] = x - i; 118 return out; 119 } 120 // Check if `x` can even have a fractional part... 121 if ( exp > 51 ) { 122 // `x` is integral: 123 out[ 0 ] = x; 124 out[ 1 ] = 0.0; 125 return out; 126 } 127 i = ALL_ONES >>> (exp-20); 128 129 // Determine if `x` is integral by checking for less significant significand bits which cannot be exponentiated away... 130 if ( (low&i) === 0 ) { 131 out[ 0 ] = x; 132 out[ 1 ] = 0.0; 133 return out; 134 } 135 // Turn off all the bits which cannot be exponentiated away: 136 low &= (~i); 137 138 // Generate the integral part: 139 i = fromWords( high, low ); 140 141 // The fractional part is whatever is leftover: 142 out[ 0 ] = i; 143 out[ 1 ] = x - i; 144 return out; 145 } 146 147 148 // EXPORTS // 149 150 module.exports = modf;