Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/math/math.js
4507 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Additional mathematical functions.
9
*/
10
11
goog.provide('goog.math');
12
13
goog.require('goog.asserts');
14
15
16
/**
17
* Returns a random integer greater than or equal to 0 and less than `a`.
18
* @param {number} a The upper bound for the random integer (exclusive).
19
* @return {number} A random integer N such that 0 <= N < a.
20
*/
21
goog.math.randomInt = function(a) {
22
'use strict';
23
return Math.floor(Math.random() * a);
24
};
25
26
27
/**
28
* Returns a random number greater than or equal to `a` and less than
29
* `b`.
30
* @param {number} a The lower bound for the random number (inclusive).
31
* @param {number} b The upper bound for the random number (exclusive).
32
* @return {number} A random number N such that a <= N < b.
33
*/
34
goog.math.uniformRandom = function(a, b) {
35
'use strict';
36
return a + Math.random() * (b - a);
37
};
38
39
40
/**
41
* Takes a number and clamps it to within the provided bounds.
42
* @param {number} value The input number.
43
* @param {number} min The minimum value to return.
44
* @param {number} max The maximum value to return.
45
* @return {number} The input number if it is within bounds, or the nearest
46
* number within the bounds.
47
*/
48
goog.math.clamp = function(value, min, max) {
49
'use strict';
50
return Math.min(Math.max(value, min), max);
51
};
52
53
54
/**
55
* The % operator in JavaScript returns the remainder of a / b, but differs from
56
* some other languages in that the result will have the same sign as the
57
* dividend. For example, -1 % 8 == -1, whereas in some other languages
58
* (such as Python) the result would be 7. This function emulates the more
59
* correct modulo behavior, which is useful for certain applications such as
60
* calculating an offset index in a circular list.
61
*
62
* @param {number} a The dividend.
63
* @param {number} b The divisor.
64
* @return {number} a % b where the result is between 0 and b (either 0 <= x < b
65
* or b < x <= 0, depending on the sign of b).
66
*/
67
goog.math.modulo = function(a, b) {
68
'use strict';
69
var r = a % b;
70
// If r and b differ in sign, add b to wrap the result to the correct sign.
71
return (r * b < 0) ? r + b : r;
72
};
73
74
75
/**
76
* Performs linear interpolation between values a and b. Returns the value
77
* between a and b proportional to x (when x is between 0 and 1. When x is
78
* outside this range, the return value is a linear extrapolation).
79
* @param {number} a A number.
80
* @param {number} b A number.
81
* @param {number} x The proportion between a and b.
82
* @return {number} The interpolated value between a and b.
83
*/
84
goog.math.lerp = function(a, b, x) {
85
'use strict';
86
return a + x * (b - a);
87
};
88
89
90
/**
91
* Tests whether the two values are equal to each other, within a certain
92
* tolerance to adjust for floating point errors.
93
* @param {number} a A number.
94
* @param {number} b A number.
95
* @param {number=} opt_tolerance Optional tolerance range. Defaults
96
* to 0.000001. If specified, should be greater than 0.
97
* @return {boolean} Whether `a` and `b` are nearly equal.
98
*/
99
goog.math.nearlyEquals = function(a, b, opt_tolerance) {
100
'use strict';
101
return Math.abs(a - b) <= (opt_tolerance || 0.000001);
102
};
103
104
105
// TODO(user): Rename to normalizeAngle, retaining old name as deprecated
106
// alias.
107
/**
108
* Normalizes an angle to be in range [0-360). Angles outside this range will
109
* be normalized to be the equivalent angle with that range.
110
* @param {number} angle Angle in degrees.
111
* @return {number} Standardized angle.
112
*/
113
goog.math.standardAngle = function(angle) {
114
'use strict';
115
return goog.math.modulo(angle, 360);
116
};
117
118
119
/**
120
* Normalizes an angle to be in range [0-2*PI). Angles outside this range will
121
* be normalized to be the equivalent angle with that range.
122
* @param {number} angle Angle in radians.
123
* @return {number} Standardized angle.
124
*/
125
goog.math.standardAngleInRadians = function(angle) {
126
'use strict';
127
return goog.math.modulo(angle, 2 * Math.PI);
128
};
129
130
131
/**
132
* Converts degrees to radians.
133
* @param {number} angleDegrees Angle in degrees.
134
* @return {number} Angle in radians.
135
*/
136
goog.math.toRadians = function(angleDegrees) {
137
'use strict';
138
return angleDegrees * Math.PI / 180;
139
};
140
141
142
/**
143
* Converts radians to degrees.
144
* @param {number} angleRadians Angle in radians.
145
* @return {number} Angle in degrees.
146
*/
147
goog.math.toDegrees = function(angleRadians) {
148
'use strict';
149
return angleRadians * 180 / Math.PI;
150
};
151
152
153
/**
154
* For a given angle and radius, finds the X portion of the offset.
155
* @param {number} degrees Angle in degrees (zero points in +X direction).
156
* @param {number} radius Radius.
157
* @return {number} The x-distance for the angle and radius.
158
*/
159
goog.math.angleDx = function(degrees, radius) {
160
'use strict';
161
return radius * Math.cos(goog.math.toRadians(degrees));
162
};
163
164
165
/**
166
* For a given angle and radius, finds the Y portion of the offset.
167
* @param {number} degrees Angle in degrees (zero points in +X direction).
168
* @param {number} radius Radius.
169
* @return {number} The y-distance for the angle and radius.
170
*/
171
goog.math.angleDy = function(degrees, radius) {
172
'use strict';
173
return radius * Math.sin(goog.math.toRadians(degrees));
174
};
175
176
177
/**
178
* Computes the angle between two points (x1,y1) and (x2,y2).
179
* Angle zero points in the +X direction, 90 degrees points in the +Y
180
* direction (down) and from there we grow clockwise towards 360 degrees.
181
* @param {number} x1 x of first point.
182
* @param {number} y1 y of first point.
183
* @param {number} x2 x of second point.
184
* @param {number} y2 y of second point.
185
* @return {number} Standardized angle in degrees of the vector from
186
* x1,y1 to x2,y2.
187
*/
188
goog.math.angle = function(x1, y1, x2, y2) {
189
'use strict';
190
return goog.math.standardAngle(
191
goog.math.toDegrees(Math.atan2(y2 - y1, x2 - x1)));
192
};
193
194
195
/**
196
* Computes the difference between startAngle and endAngle (angles in degrees).
197
* @param {number} startAngle Start angle in degrees.
198
* @param {number} endAngle End angle in degrees.
199
* @return {number} The number of degrees that when added to
200
* startAngle will result in endAngle. Positive numbers mean that the
201
* direction is clockwise. Negative numbers indicate a counter-clockwise
202
* direction.
203
* The shortest route (clockwise vs counter-clockwise) between the angles
204
* is used.
205
* When the difference is 180 degrees, the function returns 180 (not -180)
206
* angleDifference(30, 40) is 10, and angleDifference(40, 30) is -10.
207
* angleDifference(350, 10) is 20, and angleDifference(10, 350) is -20.
208
*/
209
goog.math.angleDifference = function(startAngle, endAngle) {
210
'use strict';
211
var d =
212
goog.math.standardAngle(endAngle) - goog.math.standardAngle(startAngle);
213
if (d > 180) {
214
d = d - 360;
215
} else if (d <= -180) {
216
d = 360 + d;
217
}
218
return d;
219
};
220
221
222
/**
223
* Returns the sign of a number as per the "sign" or "signum" function.
224
* @param {number} x The number to take the sign of.
225
* @return {number} -1 when negative, 1 when positive, 0 when 0. Preserves
226
* signed zeros and NaN.
227
*/
228
goog.math.sign = function(x) {
229
'use strict';
230
if (x > 0) {
231
return 1;
232
}
233
if (x < 0) {
234
return -1;
235
}
236
return x; // Preserves signed zeros and NaN.
237
};
238
239
240
/**
241
* JavaScript implementation of Longest Common Subsequence problem.
242
* http://en.wikipedia.org/wiki/Longest_common_subsequence
243
*
244
* Returns the longest possible array that is subarray of both of given arrays.
245
*
246
* @param {IArrayLike<S>} array1 First array of objects.
247
* @param {IArrayLike<T>} array2 Second array of objects.
248
* @param {Function=} opt_compareFn Function that acts as a custom comparator
249
* for the array ojects. Function should return true if objects are equal,
250
* otherwise false.
251
* @param {Function=} opt_collectorFn Function used to decide what to return
252
* as a result subsequence. It accepts 2 arguments: index of common element
253
* in the first array and index in the second. The default function returns
254
* element from the first array.
255
* @return {!Array<S|T>} A list of objects that are common to both arrays
256
* such that there is no common subsequence with size greater than the
257
* length of the list.
258
* @template S,T
259
*/
260
goog.math.longestCommonSubsequence = function(
261
array1, array2, opt_compareFn, opt_collectorFn) {
262
'use strict';
263
var compare = opt_compareFn || function(a, b) {
264
'use strict';
265
return a == b;
266
};
267
268
var collect = opt_collectorFn || function(i1, i2) {
269
'use strict';
270
return array1[i1];
271
};
272
273
var length1 = array1.length;
274
var length2 = array2.length;
275
276
var arr = [];
277
for (var i = 0; i < length1 + 1; i++) {
278
arr[i] = [];
279
arr[i][0] = 0;
280
}
281
282
for (var j = 0; j < length2 + 1; j++) {
283
arr[0][j] = 0;
284
}
285
286
for (i = 1; i <= length1; i++) {
287
for (j = 1; j <= length2; j++) {
288
if (compare(array1[i - 1], array2[j - 1])) {
289
arr[i][j] = arr[i - 1][j - 1] + 1;
290
} else {
291
arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]);
292
}
293
}
294
}
295
296
// Backtracking
297
var result = [];
298
var i = length1, j = length2;
299
while (i > 0 && j > 0) {
300
if (compare(array1[i - 1], array2[j - 1])) {
301
result.unshift(collect(i - 1, j - 1));
302
i--;
303
j--;
304
} else {
305
if (arr[i - 1][j] > arr[i][j - 1]) {
306
i--;
307
} else {
308
j--;
309
}
310
}
311
}
312
313
return result;
314
};
315
316
317
/**
318
* Returns the sum of the arguments.
319
* @param {...number} var_args Numbers to add.
320
* @return {number} The sum of the arguments (0 if no arguments were provided,
321
* `NaN` if any of the arguments is not a valid number).
322
*/
323
goog.math.sum = function(var_args) {
324
'use strict';
325
return /** @type {number} */ (
326
Array.prototype.reduce.call(arguments, function(sum, value) {
327
'use strict';
328
return sum + value;
329
}, 0));
330
};
331
332
333
/**
334
* Returns the arithmetic mean of the arguments.
335
* @param {...number} var_args Numbers to average.
336
* @return {number} The average of the arguments (`NaN` if no arguments
337
* were provided or any of the arguments is not a valid number).
338
*/
339
goog.math.average = function(var_args) {
340
'use strict';
341
return goog.math.sum.apply(null, arguments) / arguments.length;
342
};
343
344
345
/**
346
* Returns the unbiased sample variance of the arguments. For a definition,
347
* see e.g. http://en.wikipedia.org/wiki/Variance
348
* @param {...number} var_args Number samples to analyze.
349
* @return {number} The unbiased sample variance of the arguments (0 if fewer
350
* than two samples were provided, or `NaN` if any of the samples is
351
* not a valid number).
352
*/
353
goog.math.sampleVariance = function(var_args) {
354
'use strict';
355
var sampleSize = arguments.length;
356
if (sampleSize < 2) {
357
return 0;
358
}
359
360
var mean = goog.math.average.apply(null, arguments);
361
var variance = goog.math.sum.apply(
362
null,
363
Array.prototype.map.call(
364
arguments,
365
function(val) {
366
'use strict';
367
return Math.pow(val - mean, 2);
368
})) /
369
(sampleSize - 1);
370
371
return variance;
372
};
373
374
375
/**
376
* Returns the sample standard deviation of the arguments. For a definition of
377
* sample standard deviation, see e.g.
378
* http://en.wikipedia.org/wiki/Standard_deviation
379
* @param {...number} var_args Number samples to analyze.
380
* @return {number} The sample standard deviation of the arguments (0 if fewer
381
* than two samples were provided, or `NaN` if any of the samples is
382
* not a valid number).
383
*/
384
goog.math.standardDeviation = function(var_args) {
385
'use strict';
386
return Math.sqrt(goog.math.sampleVariance.apply(null, arguments));
387
};
388
389
390
/**
391
* Returns whether the supplied number represents an integer, i.e. that is has
392
* no fractional component. No range-checking is performed on the number.
393
* @param {number} num The number to test.
394
* @return {boolean} Whether `num` is an integer.
395
*/
396
goog.math.isInt = function(num) {
397
'use strict';
398
return isFinite(num) && num % 1 == 0;
399
};
400
401
402
/**
403
* Returns whether the supplied number is finite and not NaN.
404
* @param {number} num The number to test.
405
* @return {boolean} Whether `num` is a finite number.
406
* @deprecated Use {@link isFinite} instead.
407
*/
408
goog.math.isFiniteNumber = function(num) {
409
'use strict';
410
return isFinite(num);
411
};
412
413
414
/**
415
* @param {number} num The number to test.
416
* @return {boolean} Whether it is negative zero.
417
*/
418
goog.math.isNegativeZero = function(num) {
419
'use strict';
420
return num == 0 && 1 / num < 0;
421
};
422
423
424
/**
425
* Returns the precise value of floor(log10(num)).
426
* Simpler implementations didn't work because of floating point rounding
427
* errors. For example
428
* <ul>
429
* <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3.
430
* <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15.
431
* <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1.
432
* </ul>
433
* @param {number} num A floating point number.
434
* @return {number} Its logarithm to base 10 rounded down to the nearest
435
* integer if num > 0. -Infinity if num == 0. NaN if num < 0.
436
*/
437
goog.math.log10Floor = function(num) {
438
'use strict';
439
if (num > 0) {
440
var x = Math.round(Math.log(num) * Math.LOG10E);
441
return x - (parseFloat('1e' + x) > num ? 1 : 0);
442
}
443
return num == 0 ? -Infinity : NaN;
444
};
445
446
447
/**
448
* A tweaked variant of `Math.floor` which tolerates if the passed number
449
* is infinitesimally smaller than the closest integer. It often happens with
450
* the results of floating point calculations because of the finite precision
451
* of the intermediate results. For example {@code Math.floor(Math.log(1000) /
452
* Math.LN10) == 2}, not 3 as one would expect.
453
* @param {number} num A number.
454
* @param {number=} opt_epsilon An infinitesimally small positive number, the
455
* rounding error to tolerate.
456
* @return {number} The largest integer less than or equal to `num`.
457
*/
458
goog.math.safeFloor = function(num, opt_epsilon) {
459
'use strict';
460
goog.asserts.assert(opt_epsilon === undefined || opt_epsilon > 0);
461
return Math.floor(num + (opt_epsilon || 2e-15));
462
};
463
464
465
/**
466
* A tweaked variant of `Math.ceil`. See `goog.math.safeFloor` for
467
* details.
468
* @param {number} num A number.
469
* @param {number=} opt_epsilon An infinitesimally small positive number, the
470
* rounding error to tolerate.
471
* @return {number} The smallest integer greater than or equal to `num`.
472
*/
473
goog.math.safeCeil = function(num, opt_epsilon) {
474
'use strict';
475
goog.asserts.assert(opt_epsilon === undefined || opt_epsilon > 0);
476
return Math.ceil(num - (opt_epsilon || 2e-15));
477
};
478
479