simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

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 }