UNPKG

4.41 kBJavaScriptView Raw
1'use strict'
2
3const isInteger = require('../../utils/number').isInteger
4
5function factory (type, config, load, typed) {
6 const matrix = load(require('../../type/matrix/function/matrix'))
7
8 const algorithm01 = load(require('../../type/matrix/utils/algorithm01'))
9 const algorithm04 = load(require('../../type/matrix/utils/algorithm04'))
10 const algorithm10 = load(require('../../type/matrix/utils/algorithm10'))
11 const algorithm13 = load(require('../../type/matrix/utils/algorithm13'))
12 const algorithm14 = load(require('../../type/matrix/utils/algorithm14'))
13
14 /**
15 * Calculate the greatest common divisor for two or more values or arrays.
16 *
17 * For matrices, the function is evaluated element wise.
18 *
19 * Syntax:
20 *
21 * math.gcd(a, b)
22 * math.gcd(a, b, c, ...)
23 *
24 * Examples:
25 *
26 * math.gcd(8, 12) // returns 4
27 * math.gcd(-4, 6) // returns 2
28 * math.gcd(25, 15, -10) // returns 5
29 *
30 * math.gcd([8, -4], [12, 6]) // returns [4, 2]
31 *
32 * See also:
33 *
34 * lcm, xgcd
35 *
36 * @param {... number | BigNumber | Fraction | Array | Matrix} args Two or more integer numbers
37 * @return {number | BigNumber | Fraction | Array | Matrix} The greatest common divisor
38 */
39 const gcd = typed('gcd', {
40
41 'number, number': _gcd,
42
43 'BigNumber, BigNumber': _gcdBigNumber,
44
45 'Fraction, Fraction': function (x, y) {
46 return x.gcd(y)
47 },
48
49 'SparseMatrix, SparseMatrix': function (x, y) {
50 return algorithm04(x, y, gcd)
51 },
52
53 'SparseMatrix, DenseMatrix': function (x, y) {
54 return algorithm01(y, x, gcd, true)
55 },
56
57 'DenseMatrix, SparseMatrix': function (x, y) {
58 return algorithm01(x, y, gcd, false)
59 },
60
61 'DenseMatrix, DenseMatrix': function (x, y) {
62 return algorithm13(x, y, gcd)
63 },
64
65 'Array, Array': function (x, y) {
66 // use matrix implementation
67 return gcd(matrix(x), matrix(y)).valueOf()
68 },
69
70 'Array, Matrix': function (x, y) {
71 // use matrix implementation
72 return gcd(matrix(x), y)
73 },
74
75 'Matrix, Array': function (x, y) {
76 // use matrix implementation
77 return gcd(x, matrix(y))
78 },
79
80 'SparseMatrix, number | BigNumber': function (x, y) {
81 return algorithm10(x, y, gcd, false)
82 },
83
84 'DenseMatrix, number | BigNumber': function (x, y) {
85 return algorithm14(x, y, gcd, false)
86 },
87
88 'number | BigNumber, SparseMatrix': function (x, y) {
89 return algorithm10(y, x, gcd, true)
90 },
91
92 'number | BigNumber, DenseMatrix': function (x, y) {
93 return algorithm14(y, x, gcd, true)
94 },
95
96 'Array, number | BigNumber': function (x, y) {
97 // use matrix implementation
98 return algorithm14(matrix(x), y, gcd, false).valueOf()
99 },
100
101 'number | BigNumber, Array': function (x, y) {
102 // use matrix implementation
103 return algorithm14(matrix(y), x, gcd, true).valueOf()
104 },
105
106 // TODO: need a smarter notation here
107 'Array | Matrix | number | BigNumber, Array | Matrix | number | BigNumber, ...Array | Matrix | number | BigNumber': function (a, b, args) {
108 let res = gcd(a, b)
109 for (let i = 0; i < args.length; i++) {
110 res = gcd(res, args[i])
111 }
112 return res
113 }
114 })
115
116 gcd.toTex = `\\gcd\\left(\${args}\\right)`
117
118 return gcd
119
120 /**
121 * Calculate gcd for BigNumbers
122 * @param {BigNumber} a
123 * @param {BigNumber} b
124 * @returns {BigNumber} Returns greatest common denominator of a and b
125 * @private
126 */
127 function _gcdBigNumber (a, b) {
128 if (!a.isInt() || !b.isInt()) {
129 throw new Error('Parameters in function gcd must be integer numbers')
130 }
131
132 // https://en.wikipedia.org/wiki/Euclidean_algorithm
133 const zero = new type.BigNumber(0)
134 while (!b.isZero()) {
135 const r = a.mod(b)
136 a = b
137 b = r
138 }
139 return a.lt(zero) ? a.neg() : a
140 }
141}
142
143/**
144 * Calculate gcd for numbers
145 * @param {number} a
146 * @param {number} b
147 * @returns {number} Returns the greatest common denominator of a and b
148 * @private
149 */
150function _gcd (a, b) {
151 if (!isInteger(a) || !isInteger(b)) {
152 throw new Error('Parameters in function gcd must be integer numbers')
153 }
154
155 // https://en.wikipedia.org/wiki/Euclidean_algorithm
156 let r
157 while (b !== 0) {
158 r = a % b
159 a = b
160 b = r
161 }
162 return (a < 0) ? -a : a
163}
164
165exports.name = 'gcd'
166exports.factory = factory