UNPKG

3.36 kBJavaScriptView Raw
1'use strict'
2
3const Complex = require('../../type/complex/Complex')
4const typed = require('../../core/typed')
5const complex = Complex.factory(
6 'Complex', {}, '', typed, { on: function (x, y) {} }
7)
8
9function factory (type, config, load, typed) {
10 /**
11 * Calculate the nth roots of a value.
12 * An nth root of a positive real number A,
13 * is a positive real solution of the equation "x^root = A".
14 * This function returns an array of complex values.
15 *
16 * Syntax:
17 *
18 * math.nthRoots(x)
19 * math.nthRoots(x, root)
20 *
21 * Examples:
22 *
23 * math.nthRoots(1)
24 * // returns [
25 * // {re: 1, im: 0},
26 * // {re: -1, im: 0}
27 * // ]
28 * nthRoots(1, 3)
29 * // returns [
30 * // { re: 1, im: 0 },
31 * // { re: -0.4999999999999998, im: 0.8660254037844387 },
32 * // { re: -0.5000000000000004, im: -0.8660254037844385 }
33 * ]
34 *
35 * See also:
36 *
37 * nthRoot, pow, sqrt
38 *
39 * @param {number | BigNumber | Fraction | Complex | Array | Matrix} x Number to be rounded
40 * @return {number | BigNumber | Fraction | Complex | Array | Matrix} Rounded value
41 */
42 const nthRoots = typed('nthRoots', {
43 'Complex': function (x) {
44 return _nthComplexRoots(x, 2)
45 },
46 'Complex, number': _nthComplexRoots
47 })
48 nthRoots.toTex = { 2: `\\{y : $y^{args[1]} = {\${args[0]}}\\}` }
49 return nthRoots
50}
51
52/**
53 * Each function here returns a real multiple of i as a Complex value.
54 * @param {number} val
55 * @return {Complex} val, i*val, -val or -i*val for index 0, 1, 2, 3
56 */
57// This is used to fix float artifacts for zero-valued components.
58const _calculateExactResult = [
59 function realPos (val) { return complex(val) },
60 function imagPos (val) { return complex(0, val) },
61 function realNeg (val) { return complex(-val) },
62 function imagNeg (val) { return complex(0, -val) }
63]
64
65/**
66 * Calculate the nth root of a Complex Number a using De Movire's Theorem.
67 * @param {Complex} a
68 * @param {number} root
69 * @return {Array} array of n Complex Roots
70 */
71function _nthComplexRoots (a, root) {
72 if (root < 0) throw new Error('Root must be greater than zero')
73 if (root === 0) throw new Error('Root must be non-zero')
74 if (root % 1 !== 0) throw new Error('Root must be an integer')
75 if (a === 0 || a.abs() === 0) return [complex(0)]
76 const aIsNumeric = typeof (a) === 'number'
77 let offset
78 // determine the offset (argument of a)/(pi/2)
79 if (aIsNumeric || a.re === 0 || a.im === 0) {
80 if (aIsNumeric) {
81 offset = 2 * (+(a < 0)) // numeric value on the real axis
82 } else if (a.im === 0) {
83 offset = 2 * (+(a.re < 0)) // complex value on the real axis
84 } else {
85 offset = 2 * (+(a.im < 0)) + 1 // complex value on the imaginary axis
86 }
87 }
88 const arg = a.arg()
89 const abs = a.abs()
90 const roots = []
91 const r = Math.pow(abs, 1 / root)
92 for (let k = 0; k < root; k++) {
93 const halfPiFactor = (offset + 4 * k) / root
94 /**
95 * If (offset + 4*k)/root is an integral multiple of pi/2
96 * then we can produce a more exact result.
97 */
98 if (halfPiFactor === Math.round(halfPiFactor)) {
99 roots.push(_calculateExactResult[halfPiFactor % 4](r))
100 continue
101 }
102 roots.push(complex({ r: r, phi: (arg + 2 * Math.PI * k) / root }))
103 }
104 return roots
105}
106
107exports.name = 'nthRoots'
108exports.factory = factory