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