UNPKG

7.04 kBJavaScriptView Raw
1import { isInteger, log2, log10, cbrt, expm1, sign, toFixed, log1p } from '../../utils/number'
2
3const n1 = 'number'
4const n2 = 'number, number'
5
6export function absNumber (a) {
7 return Math.abs(a)
8}
9absNumber.signature = n1
10
11export function addNumber (a, b) {
12 return a + b
13}
14addNumber.signature = n2
15
16export function subtractNumber (a, b) {
17 return a - b
18}
19subtractNumber.signature = n2
20
21export function multiplyNumber (a, b) {
22 return a * b
23}
24multiplyNumber.signature = n2
25
26export function divideNumber (a, b) {
27 return a / b
28}
29divideNumber.signature = n2
30
31export function unaryMinusNumber (x) {
32 return -x
33}
34unaryMinusNumber.signature = n1
35
36export function unaryPlusNumber (x) {
37 return x
38}
39unaryPlusNumber.signature = n1
40
41export function cbrtNumber (x) {
42 return cbrt(x)
43}
44cbrtNumber.signature = n1
45
46export function ceilNumber (x) {
47 return Math.ceil(x)
48}
49ceilNumber.signature = n1
50
51export function cubeNumber (x) {
52 return x * x * x
53}
54cubeNumber.signature = n1
55
56export function expNumber (x) {
57 return Math.exp(x)
58}
59expNumber.signature = n1
60
61export function expm1Number (x) {
62 return expm1(x)
63}
64expm1Number.signature = n1
65
66export function fixNumber (x) {
67 return (x > 0) ? Math.floor(x) : Math.ceil(x)
68}
69fixNumber.signature = n1
70
71export function floorNumber (x) {
72 return Math.floor(x)
73}
74floorNumber.signature = n1
75
76/**
77 * Calculate gcd for numbers
78 * @param {number} a
79 * @param {number} b
80 * @returns {number} Returns the greatest common denominator of a and b
81 */
82export function gcdNumber (a, b) {
83 if (!isInteger(a) || !isInteger(b)) {
84 throw new Error('Parameters in function gcd must be integer numbers')
85 }
86
87 // https://en.wikipedia.org/wiki/Euclidean_algorithm
88 let r
89 while (b !== 0) {
90 r = a % b
91 a = b
92 b = r
93 }
94 return (a < 0) ? -a : a
95}
96gcdNumber.signature = n2
97
98/**
99 * Calculate lcm for two numbers
100 * @param {number} a
101 * @param {number} b
102 * @returns {number} Returns the least common multiple of a and b
103 */
104export function lcmNumber (a, b) {
105 if (!isInteger(a) || !isInteger(b)) {
106 throw new Error('Parameters in function lcm must be integer numbers')
107 }
108
109 if (a === 0 || b === 0) {
110 return 0
111 }
112
113 // https://en.wikipedia.org/wiki/Euclidean_algorithm
114 // evaluate lcm here inline to reduce overhead
115 let t
116 const prod = a * b
117 while (b !== 0) {
118 t = b
119 b = a % t
120 a = t
121 }
122 return Math.abs(prod / a)
123}
124lcmNumber.signature = n2
125
126/**
127 * Calculate the logarithm of a value.
128 * @param {number} x
129 * @return {number}
130 */
131export function logNumber (x) {
132 return Math.log(x)
133}
134logNumber.signature = n1
135
136/**
137 * Calculate the 10-base logarithm of a number
138 * @param {number} x
139 * @return {number}
140 */
141export function log10Number (x) {
142 return log10(x)
143}
144log10Number.signature = n1
145
146/**
147 * Calculate the 2-base logarithm of a number
148 * @param {number} x
149 * @return {number}
150 */
151export function log2Number (x) {
152 return log2(x)
153}
154log2Number.signature = n1
155
156/**
157 * Calculate the natural logarithm of a `number+1`
158 * @param {number} x
159 * @returns {number}
160 */
161export function log1pNumber (x) {
162 return log1p(x)
163}
164log1pNumber.signature = n1
165
166/**
167 * Calculate the modulus of two numbers
168 * @param {number} x
169 * @param {number} y
170 * @returns {number} res
171 * @private
172 */
173export function modNumber (x, y) {
174 if (y > 0) {
175 // We don't use JavaScript's % operator here as this doesn't work
176 // correctly for x < 0 and x === 0
177 // see https://en.wikipedia.org/wiki/Modulo_operation
178 return x - y * Math.floor(x / y)
179 } else if (y === 0) {
180 return x
181 } else { // y < 0
182 // TODO: implement mod for a negative divisor
183 throw new Error('Cannot calculate mod for a negative divisor')
184 }
185}
186modNumber.signature = n2
187
188/**
189 * Calculate the nth root of a, solve x^root == a
190 * http://rosettacode.org/wiki/Nth_root#JavaScript
191 * @param {number} a
192 * @param {number} root
193 * @private
194 */
195export function nthRootNumber (a, root) {
196 const inv = root < 0
197 if (inv) {
198 root = -root
199 }
200
201 if (root === 0) {
202 throw new Error('Root must be non-zero')
203 }
204 if (a < 0 && (Math.abs(root) % 2 !== 1)) {
205 throw new Error('Root must be odd when a is negative.')
206 }
207
208 // edge cases zero and infinity
209 if (a === 0) {
210 return inv ? Infinity : 0
211 }
212 if (!isFinite(a)) {
213 return inv ? 0 : a
214 }
215
216 let x = Math.pow(Math.abs(a), 1 / root)
217 // If a < 0, we require that root is an odd integer,
218 // so (-1) ^ (1/root) = -1
219 x = a < 0 ? -x : x
220 return inv ? 1 / x : x
221
222 // Very nice algorithm, but fails with nthRoot(-2, 3).
223 // Newton's method has some well-known problems at times:
224 // https://en.wikipedia.org/wiki/Newton%27s_method#Failure_analysis
225 /*
226 let x = 1 // Initial guess
227 let xPrev = 1
228 let i = 0
229 const iMax = 10000
230 do {
231 const delta = (a / Math.pow(x, root - 1) - x) / root
232 xPrev = x
233 x = x + delta
234 i++
235 }
236 while (xPrev !== x && i < iMax)
237
238 if (xPrev !== x) {
239 throw new Error('Function nthRoot failed to converge')
240 }
241
242 return inv ? 1 / x : x
243 */
244}
245nthRootNumber.signature = n2
246
247export function signNumber (x) {
248 return sign(x)
249}
250signNumber.signature = n1
251
252export function sqrtNumber (x) {
253 return Math.sqrt(x)
254}
255sqrtNumber.signature = n1
256
257export function squareNumber (x) {
258 return x * x
259}
260squareNumber.signature = n1
261
262/**
263 * Calculate xgcd for two numbers
264 * @param {number} a
265 * @param {number} b
266 * @return {number} result
267 * @private
268 */
269export function xgcdNumber (a, b) {
270 // source: https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
271 let t // used to swap two variables
272 let q // quotient
273 let r // remainder
274 let x = 0
275 let lastx = 1
276 let y = 1
277 let lasty = 0
278
279 if (!isInteger(a) || !isInteger(b)) {
280 throw new Error('Parameters in function xgcd must be integer numbers')
281 }
282
283 while (b) {
284 q = Math.floor(a / b)
285 r = a - q * b
286
287 t = x
288 x = lastx - q * x
289 lastx = t
290
291 t = y
292 y = lasty - q * y
293 lasty = t
294
295 a = b
296 b = r
297 }
298
299 let res
300 if (a < 0) {
301 res = [-a, -lastx, -lasty]
302 } else {
303 res = [a, a ? lastx : 0, lasty]
304 }
305 return res
306}
307xgcdNumber.signature = n2
308
309/**
310 * Calculates the power of x to y, x^y, for two numbers.
311 * @param {number} x
312 * @param {number} y
313 * @return {number} res
314 */
315export function powNumber (x, y) {
316 // x^Infinity === 0 if -1 < x < 1
317 // A real number 0 is returned instead of complex(0)
318 if ((x * x < 1 && y === Infinity) ||
319 (x * x > 1 && y === -Infinity)) {
320 return 0
321 }
322
323 return Math.pow(x, y)
324}
325powNumber.signature = n2
326
327/**
328 * round a number to the given number of decimals, or to zero if decimals is
329 * not provided
330 * @param {number} value
331 * @param {number} decimals number of decimals, between 0 and 15 (0 by default)
332 * @return {number} roundedValue
333 */
334export function roundNumber (value, decimals = 0) {
335 return parseFloat(toFixed(value, decimals))
336}
337roundNumber.signature = n2
338
339/**
340 * Calculate the norm of a number, the absolute value.
341 * @param {number} x
342 * @return {number}
343 */
344export function normNumber (x) {
345 return Math.abs(x)
346}
347normNumber.signature = n1