Path: blob/trunk/third_party/closure/goog/math/math.js
4507 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Additional mathematical functions.8*/910goog.provide('goog.math');1112goog.require('goog.asserts');131415/**16* Returns a random integer greater than or equal to 0 and less than `a`.17* @param {number} a The upper bound for the random integer (exclusive).18* @return {number} A random integer N such that 0 <= N < a.19*/20goog.math.randomInt = function(a) {21'use strict';22return Math.floor(Math.random() * a);23};242526/**27* Returns a random number greater than or equal to `a` and less than28* `b`.29* @param {number} a The lower bound for the random number (inclusive).30* @param {number} b The upper bound for the random number (exclusive).31* @return {number} A random number N such that a <= N < b.32*/33goog.math.uniformRandom = function(a, b) {34'use strict';35return a + Math.random() * (b - a);36};373839/**40* Takes a number and clamps it to within the provided bounds.41* @param {number} value The input number.42* @param {number} min The minimum value to return.43* @param {number} max The maximum value to return.44* @return {number} The input number if it is within bounds, or the nearest45* number within the bounds.46*/47goog.math.clamp = function(value, min, max) {48'use strict';49return Math.min(Math.max(value, min), max);50};515253/**54* The % operator in JavaScript returns the remainder of a / b, but differs from55* some other languages in that the result will have the same sign as the56* dividend. For example, -1 % 8 == -1, whereas in some other languages57* (such as Python) the result would be 7. This function emulates the more58* correct modulo behavior, which is useful for certain applications such as59* calculating an offset index in a circular list.60*61* @param {number} a The dividend.62* @param {number} b The divisor.63* @return {number} a % b where the result is between 0 and b (either 0 <= x < b64* or b < x <= 0, depending on the sign of b).65*/66goog.math.modulo = function(a, b) {67'use strict';68var r = a % b;69// If r and b differ in sign, add b to wrap the result to the correct sign.70return (r * b < 0) ? r + b : r;71};727374/**75* Performs linear interpolation between values a and b. Returns the value76* between a and b proportional to x (when x is between 0 and 1. When x is77* outside this range, the return value is a linear extrapolation).78* @param {number} a A number.79* @param {number} b A number.80* @param {number} x The proportion between a and b.81* @return {number} The interpolated value between a and b.82*/83goog.math.lerp = function(a, b, x) {84'use strict';85return a + x * (b - a);86};878889/**90* Tests whether the two values are equal to each other, within a certain91* tolerance to adjust for floating point errors.92* @param {number} a A number.93* @param {number} b A number.94* @param {number=} opt_tolerance Optional tolerance range. Defaults95* to 0.000001. If specified, should be greater than 0.96* @return {boolean} Whether `a` and `b` are nearly equal.97*/98goog.math.nearlyEquals = function(a, b, opt_tolerance) {99'use strict';100return Math.abs(a - b) <= (opt_tolerance || 0.000001);101};102103104// TODO(user): Rename to normalizeAngle, retaining old name as deprecated105// alias.106/**107* Normalizes an angle to be in range [0-360). Angles outside this range will108* be normalized to be the equivalent angle with that range.109* @param {number} angle Angle in degrees.110* @return {number} Standardized angle.111*/112goog.math.standardAngle = function(angle) {113'use strict';114return goog.math.modulo(angle, 360);115};116117118/**119* Normalizes an angle to be in range [0-2*PI). Angles outside this range will120* be normalized to be the equivalent angle with that range.121* @param {number} angle Angle in radians.122* @return {number} Standardized angle.123*/124goog.math.standardAngleInRadians = function(angle) {125'use strict';126return goog.math.modulo(angle, 2 * Math.PI);127};128129130/**131* Converts degrees to radians.132* @param {number} angleDegrees Angle in degrees.133* @return {number} Angle in radians.134*/135goog.math.toRadians = function(angleDegrees) {136'use strict';137return angleDegrees * Math.PI / 180;138};139140141/**142* Converts radians to degrees.143* @param {number} angleRadians Angle in radians.144* @return {number} Angle in degrees.145*/146goog.math.toDegrees = function(angleRadians) {147'use strict';148return angleRadians * 180 / Math.PI;149};150151152/**153* For a given angle and radius, finds the X portion of the offset.154* @param {number} degrees Angle in degrees (zero points in +X direction).155* @param {number} radius Radius.156* @return {number} The x-distance for the angle and radius.157*/158goog.math.angleDx = function(degrees, radius) {159'use strict';160return radius * Math.cos(goog.math.toRadians(degrees));161};162163164/**165* For a given angle and radius, finds the Y portion of the offset.166* @param {number} degrees Angle in degrees (zero points in +X direction).167* @param {number} radius Radius.168* @return {number} The y-distance for the angle and radius.169*/170goog.math.angleDy = function(degrees, radius) {171'use strict';172return radius * Math.sin(goog.math.toRadians(degrees));173};174175176/**177* Computes the angle between two points (x1,y1) and (x2,y2).178* Angle zero points in the +X direction, 90 degrees points in the +Y179* direction (down) and from there we grow clockwise towards 360 degrees.180* @param {number} x1 x of first point.181* @param {number} y1 y of first point.182* @param {number} x2 x of second point.183* @param {number} y2 y of second point.184* @return {number} Standardized angle in degrees of the vector from185* x1,y1 to x2,y2.186*/187goog.math.angle = function(x1, y1, x2, y2) {188'use strict';189return goog.math.standardAngle(190goog.math.toDegrees(Math.atan2(y2 - y1, x2 - x1)));191};192193194/**195* Computes the difference between startAngle and endAngle (angles in degrees).196* @param {number} startAngle Start angle in degrees.197* @param {number} endAngle End angle in degrees.198* @return {number} The number of degrees that when added to199* startAngle will result in endAngle. Positive numbers mean that the200* direction is clockwise. Negative numbers indicate a counter-clockwise201* direction.202* The shortest route (clockwise vs counter-clockwise) between the angles203* is used.204* When the difference is 180 degrees, the function returns 180 (not -180)205* angleDifference(30, 40) is 10, and angleDifference(40, 30) is -10.206* angleDifference(350, 10) is 20, and angleDifference(10, 350) is -20.207*/208goog.math.angleDifference = function(startAngle, endAngle) {209'use strict';210var d =211goog.math.standardAngle(endAngle) - goog.math.standardAngle(startAngle);212if (d > 180) {213d = d - 360;214} else if (d <= -180) {215d = 360 + d;216}217return d;218};219220221/**222* Returns the sign of a number as per the "sign" or "signum" function.223* @param {number} x The number to take the sign of.224* @return {number} -1 when negative, 1 when positive, 0 when 0. Preserves225* signed zeros and NaN.226*/227goog.math.sign = function(x) {228'use strict';229if (x > 0) {230return 1;231}232if (x < 0) {233return -1;234}235return x; // Preserves signed zeros and NaN.236};237238239/**240* JavaScript implementation of Longest Common Subsequence problem.241* http://en.wikipedia.org/wiki/Longest_common_subsequence242*243* Returns the longest possible array that is subarray of both of given arrays.244*245* @param {IArrayLike<S>} array1 First array of objects.246* @param {IArrayLike<T>} array2 Second array of objects.247* @param {Function=} opt_compareFn Function that acts as a custom comparator248* for the array ojects. Function should return true if objects are equal,249* otherwise false.250* @param {Function=} opt_collectorFn Function used to decide what to return251* as a result subsequence. It accepts 2 arguments: index of common element252* in the first array and index in the second. The default function returns253* element from the first array.254* @return {!Array<S|T>} A list of objects that are common to both arrays255* such that there is no common subsequence with size greater than the256* length of the list.257* @template S,T258*/259goog.math.longestCommonSubsequence = function(260array1, array2, opt_compareFn, opt_collectorFn) {261'use strict';262var compare = opt_compareFn || function(a, b) {263'use strict';264return a == b;265};266267var collect = opt_collectorFn || function(i1, i2) {268'use strict';269return array1[i1];270};271272var length1 = array1.length;273var length2 = array2.length;274275var arr = [];276for (var i = 0; i < length1 + 1; i++) {277arr[i] = [];278arr[i][0] = 0;279}280281for (var j = 0; j < length2 + 1; j++) {282arr[0][j] = 0;283}284285for (i = 1; i <= length1; i++) {286for (j = 1; j <= length2; j++) {287if (compare(array1[i - 1], array2[j - 1])) {288arr[i][j] = arr[i - 1][j - 1] + 1;289} else {290arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]);291}292}293}294295// Backtracking296var result = [];297var i = length1, j = length2;298while (i > 0 && j > 0) {299if (compare(array1[i - 1], array2[j - 1])) {300result.unshift(collect(i - 1, j - 1));301i--;302j--;303} else {304if (arr[i - 1][j] > arr[i][j - 1]) {305i--;306} else {307j--;308}309}310}311312return result;313};314315316/**317* Returns the sum of the arguments.318* @param {...number} var_args Numbers to add.319* @return {number} The sum of the arguments (0 if no arguments were provided,320* `NaN` if any of the arguments is not a valid number).321*/322goog.math.sum = function(var_args) {323'use strict';324return /** @type {number} */ (325Array.prototype.reduce.call(arguments, function(sum, value) {326'use strict';327return sum + value;328}, 0));329};330331332/**333* Returns the arithmetic mean of the arguments.334* @param {...number} var_args Numbers to average.335* @return {number} The average of the arguments (`NaN` if no arguments336* were provided or any of the arguments is not a valid number).337*/338goog.math.average = function(var_args) {339'use strict';340return goog.math.sum.apply(null, arguments) / arguments.length;341};342343344/**345* Returns the unbiased sample variance of the arguments. For a definition,346* see e.g. http://en.wikipedia.org/wiki/Variance347* @param {...number} var_args Number samples to analyze.348* @return {number} The unbiased sample variance of the arguments (0 if fewer349* than two samples were provided, or `NaN` if any of the samples is350* not a valid number).351*/352goog.math.sampleVariance = function(var_args) {353'use strict';354var sampleSize = arguments.length;355if (sampleSize < 2) {356return 0;357}358359var mean = goog.math.average.apply(null, arguments);360var variance = goog.math.sum.apply(361null,362Array.prototype.map.call(363arguments,364function(val) {365'use strict';366return Math.pow(val - mean, 2);367})) /368(sampleSize - 1);369370return variance;371};372373374/**375* Returns the sample standard deviation of the arguments. For a definition of376* sample standard deviation, see e.g.377* http://en.wikipedia.org/wiki/Standard_deviation378* @param {...number} var_args Number samples to analyze.379* @return {number} The sample standard deviation of the arguments (0 if fewer380* than two samples were provided, or `NaN` if any of the samples is381* not a valid number).382*/383goog.math.standardDeviation = function(var_args) {384'use strict';385return Math.sqrt(goog.math.sampleVariance.apply(null, arguments));386};387388389/**390* Returns whether the supplied number represents an integer, i.e. that is has391* no fractional component. No range-checking is performed on the number.392* @param {number} num The number to test.393* @return {boolean} Whether `num` is an integer.394*/395goog.math.isInt = function(num) {396'use strict';397return isFinite(num) && num % 1 == 0;398};399400401/**402* Returns whether the supplied number is finite and not NaN.403* @param {number} num The number to test.404* @return {boolean} Whether `num` is a finite number.405* @deprecated Use {@link isFinite} instead.406*/407goog.math.isFiniteNumber = function(num) {408'use strict';409return isFinite(num);410};411412413/**414* @param {number} num The number to test.415* @return {boolean} Whether it is negative zero.416*/417goog.math.isNegativeZero = function(num) {418'use strict';419return num == 0 && 1 / num < 0;420};421422423/**424* Returns the precise value of floor(log10(num)).425* Simpler implementations didn't work because of floating point rounding426* errors. For example427* <ul>428* <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3.429* <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15.430* <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1.431* </ul>432* @param {number} num A floating point number.433* @return {number} Its logarithm to base 10 rounded down to the nearest434* integer if num > 0. -Infinity if num == 0. NaN if num < 0.435*/436goog.math.log10Floor = function(num) {437'use strict';438if (num > 0) {439var x = Math.round(Math.log(num) * Math.LOG10E);440return x - (parseFloat('1e' + x) > num ? 1 : 0);441}442return num == 0 ? -Infinity : NaN;443};444445446/**447* A tweaked variant of `Math.floor` which tolerates if the passed number448* is infinitesimally smaller than the closest integer. It often happens with449* the results of floating point calculations because of the finite precision450* of the intermediate results. For example {@code Math.floor(Math.log(1000) /451* Math.LN10) == 2}, not 3 as one would expect.452* @param {number} num A number.453* @param {number=} opt_epsilon An infinitesimally small positive number, the454* rounding error to tolerate.455* @return {number} The largest integer less than or equal to `num`.456*/457goog.math.safeFloor = function(num, opt_epsilon) {458'use strict';459goog.asserts.assert(opt_epsilon === undefined || opt_epsilon > 0);460return Math.floor(num + (opt_epsilon || 2e-15));461};462463464/**465* A tweaked variant of `Math.ceil`. See `goog.math.safeFloor` for466* details.467* @param {number} num A number.468* @param {number=} opt_epsilon An infinitesimally small positive number, the469* rounding error to tolerate.470* @return {number} The smallest integer greater than or equal to `num`.471*/472goog.math.safeCeil = function(num, opt_epsilon) {473'use strict';474goog.asserts.assert(opt_epsilon === undefined || opt_epsilon > 0);475return Math.ceil(num - (opt_epsilon || 2e-15));476};477478479