UNPKG

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