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