simple-squiggle

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

pow.js (5557B)


      1 import { factory } from '../../utils/factory.js';
      2 import { isInteger } from '../../utils/number.js';
      3 import { arraySize as size } from '../../utils/array.js';
      4 import { powNumber } from '../../plain/number/index.js';
      5 var name = 'pow';
      6 var dependencies = ['typed', 'config', 'identity', 'multiply', 'matrix', 'fraction', 'number', 'Complex'];
      7 export var createPow = /* #__PURE__ */factory(name, dependencies, _ref => {
      8   var {
      9     typed,
     10     config,
     11     identity,
     12     multiply,
     13     matrix,
     14     number,
     15     fraction,
     16     Complex
     17   } = _ref;
     18 
     19   /**
     20    * Calculates the power of x to y, `x ^ y`.
     21    * Matrix exponentiation is supported for square matrices `x`, and positive
     22    * integer exponents `y`.
     23    *
     24    * For cubic roots of negative numbers, the function returns the principal
     25    * root by default. In order to let the function return the real root,
     26    * math.js can be configured with `math.config({predictable: true})`.
     27    * To retrieve all cubic roots of a value, use `math.cbrt(x, true)`.
     28    *
     29    * Syntax:
     30    *
     31    *    math.pow(x, y)
     32    *
     33    * Examples:
     34    *
     35    *    math.pow(2, 3)               // returns number 8
     36    *
     37    *    const a = math.complex(2, 3)
     38    *    math.pow(a, 2)                // returns Complex -5 + 12i
     39    *
     40    *    const b = [[1, 2], [4, 3]]
     41    *    math.pow(b, 2)               // returns Array [[9, 8], [16, 17]]
     42    *
     43    * See also:
     44    *
     45    *    multiply, sqrt, cbrt, nthRoot
     46    *
     47    * @param  {number | BigNumber | Complex | Unit | Array | Matrix} x  The base
     48    * @param  {number | BigNumber | Complex} y                          The exponent
     49    * @return {number | BigNumber | Complex | Array | Matrix} The value of `x` to the power `y`
     50    */
     51   return typed(name, {
     52     'number, number': _pow,
     53     'Complex, Complex': function ComplexComplex(x, y) {
     54       return x.pow(y);
     55     },
     56     'BigNumber, BigNumber': function BigNumberBigNumber(x, y) {
     57       if (y.isInteger() || x >= 0 || config.predictable) {
     58         return x.pow(y);
     59       } else {
     60         return new Complex(x.toNumber(), 0).pow(y.toNumber(), 0);
     61       }
     62     },
     63     'Fraction, Fraction': function FractionFraction(x, y) {
     64       var result = x.pow(y);
     65 
     66       if (result != null) {
     67         return result;
     68       }
     69 
     70       if (config.predictable) {
     71         throw new Error('Result of pow is non-rational and cannot be expressed as a fraction');
     72       } else {
     73         return _pow(x.valueOf(), y.valueOf());
     74       }
     75     },
     76     'Array, number': _powArray,
     77     'Array, BigNumber': function ArrayBigNumber(x, y) {
     78       return _powArray(x, y.toNumber());
     79     },
     80     'Matrix, number': _powMatrix,
     81     'Matrix, BigNumber': function MatrixBigNumber(x, y) {
     82       return _powMatrix(x, y.toNumber());
     83     },
     84     'Unit, number | BigNumber': function UnitNumberBigNumber(x, y) {
     85       return x.pow(y);
     86     }
     87   });
     88   /**
     89    * Calculates the power of x to y, x^y, for two numbers.
     90    * @param {number} x
     91    * @param {number} y
     92    * @return {number | Complex} res
     93    * @private
     94    */
     95 
     96   function _pow(x, y) {
     97     // Alternatively could define a 'realmode' config option or something, but
     98     // 'predictable' will work for now
     99     if (config.predictable && !isInteger(y) && x < 0) {
    100       // Check to see if y can be represented as a fraction
    101       try {
    102         var yFrac = fraction(y);
    103         var yNum = number(yFrac);
    104 
    105         if (y === yNum || Math.abs((y - yNum) / y) < 1e-14) {
    106           if (yFrac.d % 2 === 1) {
    107             return (yFrac.n % 2 === 0 ? 1 : -1) * Math.pow(-x, y);
    108           }
    109         }
    110       } catch (ex) {// fraction() throws an error if y is Infinity, etc.
    111       } // Unable to express y as a fraction, so continue on
    112 
    113     } // **for predictable mode** x^Infinity === NaN if x < -1
    114     // N.B. this behavour is different from `Math.pow` which gives
    115     // (-2)^Infinity === Infinity
    116 
    117 
    118     if (config.predictable && (x < -1 && y === Infinity || x > -1 && x < 0 && y === -Infinity)) {
    119       return NaN;
    120     }
    121 
    122     if (isInteger(y) || x >= 0 || config.predictable) {
    123       return powNumber(x, y);
    124     } else {
    125       // TODO: the following infinity checks are duplicated from powNumber. Deduplicate this somehow
    126       // x^Infinity === 0 if -1 < x < 1
    127       // A real number 0 is returned instead of complex(0)
    128       if (x * x < 1 && y === Infinity || x * x > 1 && y === -Infinity) {
    129         return 0;
    130       }
    131 
    132       return new Complex(x, 0).pow(y, 0);
    133     }
    134   }
    135   /**
    136    * Calculate the power of a 2d array
    137    * @param {Array} x     must be a 2 dimensional, square matrix
    138    * @param {number} y    a positive, integer value
    139    * @returns {Array}
    140    * @private
    141    */
    142 
    143 
    144   function _powArray(x, y) {
    145     if (!isInteger(y) || y < 0) {
    146       throw new TypeError('For A^b, b must be a positive integer (value is ' + y + ')');
    147     } // verify that A is a 2 dimensional square matrix
    148 
    149 
    150     var s = size(x);
    151 
    152     if (s.length !== 2) {
    153       throw new Error('For A^b, A must be 2 dimensional (A has ' + s.length + ' dimensions)');
    154     }
    155 
    156     if (s[0] !== s[1]) {
    157       throw new Error('For A^b, A must be square (size is ' + s[0] + 'x' + s[1] + ')');
    158     }
    159 
    160     var res = identity(s[0]).valueOf();
    161     var px = x;
    162 
    163     while (y >= 1) {
    164       if ((y & 1) === 1) {
    165         res = multiply(px, res);
    166       }
    167 
    168       y >>= 1;
    169       px = multiply(px, px);
    170     }
    171 
    172     return res;
    173   }
    174   /**
    175    * Calculate the power of a 2d matrix
    176    * @param {Matrix} x     must be a 2 dimensional, square matrix
    177    * @param {number} y    a positive, integer value
    178    * @returns {Matrix}
    179    * @private
    180    */
    181 
    182 
    183   function _powMatrix(x, y) {
    184     return matrix(_powArray(x.valueOf(), y));
    185   }
    186 });