UNPKG

5.96 kBJavaScriptView Raw
1import { factory } from '../../utils/factory'
2import { createAlgorithm01 } from '../../type/matrix/utils/algorithm01'
3import { createAlgorithm02 } from '../../type/matrix/utils/algorithm02'
4import { createAlgorithm06 } from '../../type/matrix/utils/algorithm06'
5import { createAlgorithm11 } from '../../type/matrix/utils/algorithm11'
6import { createAlgorithm13 } from '../../type/matrix/utils/algorithm13'
7import { createAlgorithm14 } from '../../type/matrix/utils/algorithm14'
8import { nthRootNumber } from '../../plain/number'
9
10const name = 'nthRoot'
11const dependencies = [
12 'typed',
13 'matrix',
14 'equalScalar',
15 'BigNumber'
16]
17
18export const createNthRoot = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, equalScalar, BigNumber }) => {
19 const algorithm01 = createAlgorithm01({ typed })
20 const algorithm02 = createAlgorithm02({ typed, equalScalar })
21 const algorithm06 = createAlgorithm06({ typed, equalScalar })
22 const algorithm11 = createAlgorithm11({ typed, equalScalar })
23 const algorithm13 = createAlgorithm13({ typed })
24 const algorithm14 = createAlgorithm14({ typed })
25
26 /**
27 * Calculate the nth root of a value.
28 * The principal nth root of a positive real number A, is the positive real
29 * solution of the equation
30 *
31 * x^root = A
32 *
33 * For matrices, the function is evaluated element wise.
34 *
35 * Syntax:
36 *
37 * math.nthRoot(a)
38 * math.nthRoot(a, root)
39 *
40 * Examples:
41 *
42 * math.nthRoot(9, 2) // returns 3, as 3^2 == 9
43 * math.sqrt(9) // returns 3, as 3^2 == 9
44 * math.nthRoot(64, 3) // returns 4, as 4^3 == 64
45 *
46 * See also:
47 *
48 * sqrt, pow
49 *
50 * @param {number | BigNumber | Array | Matrix | Complex} a
51 * Value for which to calculate the nth root
52 * @param {number | BigNumber} [root=2] The root.
53 * @return {number | Complex | Array | Matrix} Returns the nth root of `a`
54 */
55 const complexErr = ('' +
56 'Complex number not supported in function nthRoot. ' +
57 'Use nthRoots instead.'
58 )
59 const nthRoot = typed(name, {
60
61 number: function (x) {
62 return nthRootNumber(x, 2)
63 },
64
65 'number, number': nthRootNumber,
66
67 BigNumber: function (x) {
68 return _bigNthRoot(x, new BigNumber(2))
69 },
70 Complex: function (x) {
71 throw new Error(complexErr)
72 },
73 'Complex, number': function (x, y) {
74 throw new Error(complexErr)
75 },
76 'BigNumber, BigNumber': _bigNthRoot,
77
78 'Array | Matrix': function (x) {
79 return nthRoot(x, 2)
80 },
81
82 'SparseMatrix, SparseMatrix': function (x, y) {
83 // density must be one (no zeros in matrix)
84 if (y.density() === 1) {
85 // sparse + sparse
86 return algorithm06(x, y, nthRoot)
87 } else {
88 // throw exception
89 throw new Error('Root must be non-zero')
90 }
91 },
92
93 'SparseMatrix, DenseMatrix': function (x, y) {
94 return algorithm02(y, x, nthRoot, true)
95 },
96
97 'DenseMatrix, SparseMatrix': function (x, y) {
98 // density must be one (no zeros in matrix)
99 if (y.density() === 1) {
100 // dense + sparse
101 return algorithm01(x, y, nthRoot, false)
102 } else {
103 // throw exception
104 throw new Error('Root must be non-zero')
105 }
106 },
107
108 'DenseMatrix, DenseMatrix': function (x, y) {
109 return algorithm13(x, y, nthRoot)
110 },
111
112 'Array, Array': function (x, y) {
113 // use matrix implementation
114 return nthRoot(matrix(x), matrix(y)).valueOf()
115 },
116
117 'Array, Matrix': function (x, y) {
118 // use matrix implementation
119 return nthRoot(matrix(x), y)
120 },
121
122 'Matrix, Array': function (x, y) {
123 // use matrix implementation
124 return nthRoot(x, matrix(y))
125 },
126
127 'SparseMatrix, number | BigNumber': function (x, y) {
128 return algorithm11(x, y, nthRoot, false)
129 },
130
131 'DenseMatrix, number | BigNumber': function (x, y) {
132 return algorithm14(x, y, nthRoot, false)
133 },
134
135 'number | BigNumber, SparseMatrix': function (x, y) {
136 // density must be one (no zeros in matrix)
137 if (y.density() === 1) {
138 // sparse - scalar
139 return algorithm11(y, x, nthRoot, true)
140 } else {
141 // throw exception
142 throw new Error('Root must be non-zero')
143 }
144 },
145
146 'number | BigNumber, DenseMatrix': function (x, y) {
147 return algorithm14(y, x, nthRoot, true)
148 },
149
150 'Array, number | BigNumber': function (x, y) {
151 // use matrix implementation
152 return nthRoot(matrix(x), y).valueOf()
153 },
154
155 'number | BigNumber, Array': function (x, y) {
156 // use matrix implementation
157 return nthRoot(x, matrix(y)).valueOf()
158 }
159 })
160
161 return nthRoot
162
163 /**
164 * Calculate the nth root of a for BigNumbers, solve x^root == a
165 * https://rosettacode.org/wiki/Nth_root#JavaScript
166 * @param {BigNumber} a
167 * @param {BigNumber} root
168 * @private
169 */
170 function _bigNthRoot (a, root) {
171 const precision = BigNumber.precision
172 const Big = BigNumber.clone({ precision: precision + 2 })
173 const zero = new BigNumber(0)
174
175 const one = new Big(1)
176 const inv = root.isNegative()
177 if (inv) {
178 root = root.neg()
179 }
180
181 if (root.isZero()) {
182 throw new Error('Root must be non-zero')
183 }
184 if (a.isNegative() && !root.abs().mod(2).equals(1)) {
185 throw new Error('Root must be odd when a is negative.')
186 }
187
188 // edge cases zero and infinity
189 if (a.isZero()) {
190 return inv ? new Big(Infinity) : 0
191 }
192 if (!a.isFinite()) {
193 return inv ? zero : a
194 }
195
196 let x = a.abs().pow(one.div(root))
197 // If a < 0, we require that root is an odd integer,
198 // so (-1) ^ (1/root) = -1
199 x = a.isNeg() ? x.neg() : x
200 return new BigNumber((inv ? one.div(x) : x).toPrecision(precision))
201 }
202})
203
204export const createNthRootNumber = /* #__PURE__ */ factory(name, ['typed'], ({ typed }) => {
205 return typed(name, {
206 number: nthRootNumber,
207 'number, number': nthRootNumber
208 })
209})