formatter.js (10547B)
1 "use strict"; 2 3 Object.defineProperty(exports, "__esModule", { 4 value: true 5 }); 6 exports.format = format; 7 exports.toEngineering = toEngineering; 8 exports.toExponential = toExponential; 9 exports.toFixed = toFixed; 10 11 var _number = require("../number.js"); 12 13 /** 14 * Formats a BigNumber in a given base 15 * @param {BigNumber} n 16 * @param {number} base 17 * @param {number} size 18 * @returns {string} 19 */ 20 function formatBigNumberToBase(n, base, size) { 21 var BigNumberCtor = n.constructor; 22 var big2 = new BigNumberCtor(2); 23 var suffix = ''; 24 25 if (size) { 26 if (size < 1) { 27 throw new Error('size must be in greater than 0'); 28 } 29 30 if (!(0, _number.isInteger)(size)) { 31 throw new Error('size must be an integer'); 32 } 33 34 if (n.greaterThan(big2.pow(size - 1).sub(1)) || n.lessThan(big2.pow(size - 1).mul(-1))) { 35 throw new Error("Value must be in range [-2^".concat(size - 1, ", 2^").concat(size - 1, "-1]")); 36 } 37 38 if (!n.isInteger()) { 39 throw new Error('Value must be an integer'); 40 } 41 42 if (n.lessThan(0)) { 43 n = n.add(big2.pow(size)); 44 } 45 46 suffix = "i".concat(size); 47 } 48 49 switch (base) { 50 case 2: 51 return "".concat(n.toBinary()).concat(suffix); 52 53 case 8: 54 return "".concat(n.toOctal()).concat(suffix); 55 56 case 16: 57 return "".concat(n.toHexadecimal()).concat(suffix); 58 59 default: 60 throw new Error("Base ".concat(base, " not supported ")); 61 } 62 } 63 /** 64 * Convert a BigNumber to a formatted string representation. 65 * 66 * Syntax: 67 * 68 * format(value) 69 * format(value, options) 70 * format(value, precision) 71 * format(value, fn) 72 * 73 * Where: 74 * 75 * {number} value The value to be formatted 76 * {Object} options An object with formatting options. Available options: 77 * {string} notation 78 * Number notation. Choose from: 79 * 'fixed' Always use regular number notation. 80 * For example '123.40' and '14000000' 81 * 'exponential' Always use exponential notation. 82 * For example '1.234e+2' and '1.4e+7' 83 * 'auto' (default) Regular number notation for numbers 84 * having an absolute value between 85 * `lower` and `upper` bounds, and uses 86 * exponential notation elsewhere. 87 * Lower bound is included, upper bound 88 * is excluded. 89 * For example '123.4' and '1.4e7'. 90 * 'bin', 'oct, or 91 * 'hex' Format the number using binary, octal, 92 * or hexadecimal notation. 93 * For example '0b1101' and '0x10fe'. 94 * {number} wordSize The word size in bits to use for formatting 95 * in binary, octal, or hexadecimal notation. 96 * To be used only with 'bin', 'oct', or 'hex' 97 * values for 'notation' option. When this option 98 * is defined the value is formatted as a signed 99 * twos complement integer of the given word size 100 * and the size suffix is appended to the output. 101 * For example 102 * format(-1, {notation: 'hex', wordSize: 8}) === '0xffi8'. 103 * Default value is undefined. 104 * {number} precision A number between 0 and 16 to round 105 * the digits of the number. 106 * In case of notations 'exponential', 107 * 'engineering', and 'auto', 108 * `precision` defines the total 109 * number of significant digits returned. 110 * In case of notation 'fixed', 111 * `precision` defines the number of 112 * significant digits after the decimal 113 * point. 114 * `precision` is undefined by default. 115 * {number} lowerExp Exponent determining the lower boundary 116 * for formatting a value with an exponent 117 * when `notation='auto`. 118 * Default value is `-3`. 119 * {number} upperExp Exponent determining the upper boundary 120 * for formatting a value with an exponent 121 * when `notation='auto`. 122 * Default value is `5`. 123 * {Function} fn A custom formatting function. Can be used to override the 124 * built-in notations. Function `fn` is called with `value` as 125 * parameter and must return a string. Is useful for example to 126 * format all values inside a matrix in a particular way. 127 * 128 * Examples: 129 * 130 * format(6.4) // '6.4' 131 * format(1240000) // '1.24e6' 132 * format(1/3) // '0.3333333333333333' 133 * format(1/3, 3) // '0.333' 134 * format(21385, 2) // '21000' 135 * format(12e8, {notation: 'fixed'}) // returns '1200000000' 136 * format(2.3, {notation: 'fixed', precision: 4}) // returns '2.3000' 137 * format(52.8, {notation: 'exponential'}) // returns '5.28e+1' 138 * format(12400, {notation: 'engineering'}) // returns '12.400e+3' 139 * 140 * @param {BigNumber} value 141 * @param {Object | Function | number} [options] 142 * @return {string} str The formatted value 143 */ 144 145 146 function format(value, options) { 147 if (typeof options === 'function') { 148 // handle format(value, fn) 149 return options(value); 150 } // handle special cases 151 152 153 if (!value.isFinite()) { 154 return value.isNaN() ? 'NaN' : value.gt(0) ? 'Infinity' : '-Infinity'; 155 } // default values for options 156 157 158 var notation = 'auto'; 159 var precision; 160 var wordSize; 161 162 if (options !== undefined) { 163 // determine notation from options 164 if (options.notation) { 165 notation = options.notation; 166 } // determine precision from options 167 168 169 if (typeof options === 'number') { 170 precision = options; 171 } else if (options.precision) { 172 precision = options.precision; 173 } 174 175 if (options.wordSize) { 176 wordSize = options.wordSize; 177 178 if (typeof wordSize !== 'number') { 179 throw new Error('Option "wordSize" must be a number'); 180 } 181 } 182 } // handle the various notations 183 184 185 switch (notation) { 186 case 'fixed': 187 return toFixed(value, precision); 188 189 case 'exponential': 190 return toExponential(value, precision); 191 192 case 'engineering': 193 return toEngineering(value, precision); 194 195 case 'bin': 196 return formatBigNumberToBase(value, 2, wordSize); 197 198 case 'oct': 199 return formatBigNumberToBase(value, 8, wordSize); 200 201 case 'hex': 202 return formatBigNumberToBase(value, 16, wordSize); 203 204 case 'auto': 205 { 206 // determine lower and upper bound for exponential notation. 207 // TODO: implement support for upper and lower to be BigNumbers themselves 208 var lowerExp = options && options.lowerExp !== undefined ? options.lowerExp : -3; 209 var upperExp = options && options.upperExp !== undefined ? options.upperExp : 5; // handle special case zero 210 211 if (value.isZero()) return '0'; // determine whether or not to output exponential notation 212 213 var str; 214 var rounded = value.toSignificantDigits(precision); 215 var exp = rounded.e; 216 217 if (exp >= lowerExp && exp < upperExp) { 218 // normal number notation 219 str = rounded.toFixed(); 220 } else { 221 // exponential notation 222 str = toExponential(value, precision); 223 } // remove trailing zeros after the decimal point 224 225 226 return str.replace(/((\.\d*?)(0+))($|e)/, function () { 227 var digits = arguments[2]; 228 var e = arguments[4]; 229 return digits !== '.' ? digits + e : e; 230 }); 231 } 232 233 default: 234 throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", "fixed", "bin", "oct", or "hex.'); 235 } 236 } 237 /** 238 * Format a BigNumber in engineering notation. Like '1.23e+6', '2.3e+0', '3.500e-3' 239 * @param {BigNumber | string} value 240 * @param {number} [precision] Optional number of significant figures to return. 241 */ 242 243 244 function toEngineering(value, precision) { 245 // find nearest lower multiple of 3 for exponent 246 var e = value.e; 247 var newExp = e % 3 === 0 ? e : e < 0 ? e - 3 - e % 3 : e - e % 3; // find difference in exponents, and calculate the value without exponent 248 249 var valueWithoutExp = value.mul(Math.pow(10, -newExp)); 250 var valueStr = valueWithoutExp.toPrecision(precision); 251 252 if (valueStr.indexOf('e') !== -1) { 253 valueStr = valueWithoutExp.toString(); 254 } 255 256 return valueStr + 'e' + (e >= 0 ? '+' : '') + newExp.toString(); 257 } 258 /** 259 * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3' 260 * @param {BigNumber} value 261 * @param {number} [precision] Number of digits in formatted output. 262 * If not provided, the maximum available digits 263 * is used. 264 * @returns {string} str 265 */ 266 267 268 function toExponential(value, precision) { 269 if (precision !== undefined) { 270 return value.toExponential(precision - 1); // Note the offset of one 271 } else { 272 return value.toExponential(); 273 } 274 } 275 /** 276 * Format a number with fixed notation. 277 * @param {BigNumber} value 278 * @param {number} [precision=undefined] Optional number of decimals after the 279 * decimal point. Undefined by default. 280 */ 281 282 283 function toFixed(value, precision) { 284 return value.toFixed(precision); 285 }