main.js (5305B)
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 PINF = require( '@stdlib/constants/float64/pinf' ); 24 var NINF = require( '@stdlib/constants/float64/ninf' ); 25 var BIAS = require( '@stdlib/constants/float64/exponent-bias' ); 26 var isnan = require( '@stdlib/math/base/assert/is-nan' ); 27 var isNegativeZero = require( '@stdlib/math/base/assert/is-negative-zero' ); 28 var abs = require( '@stdlib/math/base/special/abs' ); 29 var floor = require( '@stdlib/math/base/special/floor' ); 30 var rpad = require( '@stdlib/string/right-pad' ); 31 var lpad = require( '@stdlib/string/left-pad' ); 32 var repeat = require( '@stdlib/string/repeat' ); 33 var div2 = require( './div2.js' ); 34 var mult2 = require( './mult2.js' ); 35 36 37 // VARIABLES // 38 39 // TODO: consider moving to external constants 40 var NUM_EXPONENT_BITS = 11; 41 var NUM_SIGNIFICAND_BITS = 52; 42 43 44 // MAIN // 45 46 /** 47 * Returns a string giving the literal bit representation of a double-precision floating-point number. 48 * 49 * @param {number} x - input value 50 * @returns {BinaryString} bit representation 51 * 52 * @example 53 * var str = toBinaryString( 4.0 ); 54 * // returns '0100000000010000000000000000000000000000000000000000000000000000' 55 * 56 * @example 57 * var str = toBinaryString( 3.141592653589793 ); 58 * // returns '0100000000001001001000011111101101010100010001000010110100011000' 59 * 60 * @example 61 * var str = toBinaryString( -1.0e308 ); 62 * // returns '1111111111100001110011001111001110000101111010111100100010100000' 63 * 64 * @example 65 * var str = toBinaryString( -3.14e-320 ); 66 * // returns '1000000000000000000000000000000000000000000000000001100011010011' 67 * 68 * @example 69 * var str = toBinaryString( 5.0e-324 ); 70 * // returns '0000000000000000000000000000000000000000000000000000000000000001' 71 * 72 * @example 73 * var str = toBinaryString( 0.0 ); 74 * // returns '0000000000000000000000000000000000000000000000000000000000000000' 75 * 76 * @example 77 * var str = toBinaryString( -0.0 ); 78 * // returns '1000000000000000000000000000000000000000000000000000000000000000' 79 * 80 * @example 81 * var str = toBinaryString( NaN ); 82 * // returns '0111111111111000000000000000000000000000000000000000000000000000' 83 * 84 * @example 85 * var str = toBinaryString( Infinity ); 86 * // returns '0111111111110000000000000000000000000000000000000000000000000000' 87 * 88 * @example 89 * var str = toBinaryString( -Infinity ); 90 * // returns '1111111111110000000000000000000000000000000000000000000000000000' 91 */ 92 function toBinaryString( x ) { 93 var nbits; 94 var sign; 95 var str; 96 var exp; 97 var n; 98 var f; 99 var i; 100 101 // Check for a negative value or negative zero... 102 if ( x < 0.0 || isNegativeZero( x ) ) { 103 sign = '1'; 104 } else { 105 sign = '0'; 106 } 107 // Special case: +-infinity 108 if ( x === PINF || x === NINF ) { 109 // Based on IEEE 754-1985... 110 exp = repeat( '1', NUM_EXPONENT_BITS ); // all 1s 111 str = repeat( '0', NUM_SIGNIFICAND_BITS ); // all 0s 112 return sign + exp + str; 113 } 114 // Special case: NaN 115 if ( isnan( x ) ) { 116 // Based on IEEE 754-1985... 117 exp = repeat( '1', NUM_EXPONENT_BITS ); // all 1s 118 str = '1' + repeat( '0', NUM_SIGNIFICAND_BITS-1 ); // can't be all 0s 119 return sign + exp + str; 120 } 121 // Special case: +-0 122 if ( x === 0 ) { 123 // Based on IEEE 754-1985... 124 exp = repeat( '0', NUM_EXPONENT_BITS ); // all 0s 125 str = repeat( '0', NUM_SIGNIFICAND_BITS ); // all 0s 126 return sign + exp + str; 127 } 128 x = abs( x ); 129 130 // Isolate the integer part (digits before the decimal): 131 n = floor( x ); 132 133 // Isolate the fractional part (digits after the decimal): 134 f = x - n; 135 136 // Convert the integer and fractional parts to bit strings: 137 n = div2( n ); 138 f = mult2( f ); 139 140 // Determine the exponent needed to normalize the integer+fractional parts... 141 if ( n ) { 142 // Move the decimal `d` digits to the left: 143 exp = n.length - 1; 144 } else { 145 // Find the first '1' bit... 146 for ( i = 0; i < f.length; i++ ) { 147 if ( f[ i ] === '1' ) { 148 nbits = i + 1; 149 break; 150 } 151 } 152 // Move the decimal `d` digits to the right: 153 exp = -nbits; 154 } 155 // Normalize the combined integer+fractional string... 156 str = n + f; 157 if ( exp < 0 ) { 158 // Handle subnormals... 159 if ( exp <= -BIAS ) { 160 // Cap the number of bits removed: 161 nbits = BIAS - 1; 162 } 163 // Remove all leading zeros and the first '1' for normal values, and, for subnormals, remove at most BIAS-1 leading bits: 164 str = str.substring( nbits ); 165 } else { 166 // Remove the leading '1' (implicit/hidden bit): 167 str = str.substring( 1 ); 168 } 169 // Convert the exponent to a bit string: 170 exp = div2( exp + BIAS ); 171 exp = lpad( exp, NUM_EXPONENT_BITS, '0' ); 172 173 // Fill in any trailing zeros and ensure we have only 52 fraction bits: 174 str = rpad( str, NUM_SIGNIFICAND_BITS, '0' ).substring( 0, NUM_SIGNIFICAND_BITS ); 175 176 // Return a bit representation: 177 return sign + exp + str; 178 } 179 180 181 // EXPORTS // 182 183 module.exports = toBinaryString;