Path: blob/trunk/third_party/closure/goog/math/math.js
2868 views
// Copyright 2006 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Additional mathematical functions.16*/1718goog.provide('goog.math');1920goog.require('goog.array');21goog.require('goog.asserts');222324/**25* Returns a random integer greater than or equal to 0 and less than {@code a}.26* @param {number} a The upper bound for the random integer (exclusive).27* @return {number} A random integer N such that 0 <= N < a.28*/29goog.math.randomInt = function(a) {30return Math.floor(Math.random() * a);31};323334/**35* Returns a random number greater than or equal to {@code a} and less than36* {@code b}.37* @param {number} a The lower bound for the random number (inclusive).38* @param {number} b The upper bound for the random number (exclusive).39* @return {number} A random number N such that a <= N < b.40*/41goog.math.uniformRandom = function(a, b) {42return a + Math.random() * (b - a);43};444546/**47* Takes a number and clamps it to within the provided bounds.48* @param {number} value The input number.49* @param {number} min The minimum value to return.50* @param {number} max The maximum value to return.51* @return {number} The input number if it is within bounds, or the nearest52* number within the bounds.53*/54goog.math.clamp = function(value, min, max) {55return Math.min(Math.max(value, min), max);56};575859/**60* The % operator in JavaScript returns the remainder of a / b, but differs from61* some other languages in that the result will have the same sign as the62* dividend. For example, -1 % 8 == -1, whereas in some other languages63* (such as Python) the result would be 7. This function emulates the more64* correct modulo behavior, which is useful for certain applications such as65* calculating an offset index in a circular list.66*67* @param {number} a The dividend.68* @param {number} b The divisor.69* @return {number} a % b where the result is between 0 and b (either 0 <= x < b70* or b < x <= 0, depending on the sign of b).71*/72goog.math.modulo = function(a, b) {73var r = a % b;74// If r and b differ in sign, add b to wrap the result to the correct sign.75return (r * b < 0) ? r + b : r;76};777879/**80* Performs linear interpolation between values a and b. Returns the value81* between a and b proportional to x (when x is between 0 and 1. When x is82* outside this range, the return value is a linear extrapolation).83* @param {number} a A number.84* @param {number} b A number.85* @param {number} x The proportion between a and b.86* @return {number} The interpolated value between a and b.87*/88goog.math.lerp = function(a, b, x) {89return a + x * (b - a);90};919293/**94* Tests whether the two values are equal to each other, within a certain95* tolerance to adjust for floating point errors.96* @param {number} a A number.97* @param {number} b A number.98* @param {number=} opt_tolerance Optional tolerance range. Defaults99* to 0.000001. If specified, should be greater than 0.100* @return {boolean} Whether {@code a} and {@code b} are nearly equal.101*/102goog.math.nearlyEquals = function(a, b, opt_tolerance) {103return Math.abs(a - b) <= (opt_tolerance || 0.000001);104};105106107// TODO(user): Rename to normalizeAngle, retaining old name as deprecated108// alias.109/**110* Normalizes an angle to be in range [0-360). Angles outside this range will111* be normalized to be the equivalent angle with that range.112* @param {number} angle Angle in degrees.113* @return {number} Standardized angle.114*/115goog.math.standardAngle = function(angle) {116return goog.math.modulo(angle, 360);117};118119120/**121* Normalizes an angle to be in range [0-2*PI). Angles outside this range will122* be normalized to be the equivalent angle with that range.123* @param {number} angle Angle in radians.124* @return {number} Standardized angle.125*/126goog.math.standardAngleInRadians = function(angle) {127return goog.math.modulo(angle, 2 * Math.PI);128};129130131/**132* Converts degrees to radians.133* @param {number} angleDegrees Angle in degrees.134* @return {number} Angle in radians.135*/136goog.math.toRadians = function(angleDegrees) {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) {147return angleRadians * 180 / Math.PI;148};149150151/**152* For a given angle and radius, finds the X portion of the offset.153* @param {number} degrees Angle in degrees (zero points in +X direction).154* @param {number} radius Radius.155* @return {number} The x-distance for the angle and radius.156*/157goog.math.angleDx = function(degrees, radius) {158return radius * Math.cos(goog.math.toRadians(degrees));159};160161162/**163* For a given angle and radius, finds the Y portion of the offset.164* @param {number} degrees Angle in degrees (zero points in +X direction).165* @param {number} radius Radius.166* @return {number} The y-distance for the angle and radius.167*/168goog.math.angleDy = function(degrees, radius) {169return radius * Math.sin(goog.math.toRadians(degrees));170};171172173/**174* Computes the angle between two points (x1,y1) and (x2,y2).175* Angle zero points in the +X direction, 90 degrees points in the +Y176* direction (down) and from there we grow clockwise towards 360 degrees.177* @param {number} x1 x of first point.178* @param {number} y1 y of first point.179* @param {number} x2 x of second point.180* @param {number} y2 y of second point.181* @return {number} Standardized angle in degrees of the vector from182* x1,y1 to x2,y2.183*/184goog.math.angle = function(x1, y1, x2, y2) {185return goog.math.standardAngle(186goog.math.toDegrees(Math.atan2(y2 - y1, x2 - x1)));187};188189190/**191* Computes the difference between startAngle and endAngle (angles in degrees).192* @param {number} startAngle Start angle in degrees.193* @param {number} endAngle End angle in degrees.194* @return {number} The number of degrees that when added to195* startAngle will result in endAngle. Positive numbers mean that the196* direction is clockwise. Negative numbers indicate a counter-clockwise197* direction.198* The shortest route (clockwise vs counter-clockwise) between the angles199* is used.200* When the difference is 180 degrees, the function returns 180 (not -180)201* angleDifference(30, 40) is 10, and angleDifference(40, 30) is -10.202* angleDifference(350, 10) is 20, and angleDifference(10, 350) is -20.203*/204goog.math.angleDifference = function(startAngle, endAngle) {205var d =206goog.math.standardAngle(endAngle) - goog.math.standardAngle(startAngle);207if (d > 180) {208d = d - 360;209} else if (d <= -180) {210d = 360 + d;211}212return d;213};214215216/**217* Returns the sign of a number as per the "sign" or "signum" function.218* @param {number} x The number to take the sign of.219* @return {number} -1 when negative, 1 when positive, 0 when 0. Preserves220* signed zeros and NaN.221*/222goog.math.sign = function(x) {223if (x > 0) {224return 1;225}226if (x < 0) {227return -1;228}229return x; // Preserves signed zeros and NaN.230};231232233/**234* JavaScript implementation of Longest Common Subsequence problem.235* http://en.wikipedia.org/wiki/Longest_common_subsequence236*237* Returns the longest possible array that is subarray of both of given arrays.238*239* @param {IArrayLike<S>} array1 First array of objects.240* @param {IArrayLike<T>} array2 Second array of objects.241* @param {Function=} opt_compareFn Function that acts as a custom comparator242* for the array ojects. Function should return true if objects are equal,243* otherwise false.244* @param {Function=} opt_collectorFn Function used to decide what to return245* as a result subsequence. It accepts 2 arguments: index of common element246* in the first array and index in the second. The default function returns247* element from the first array.248* @return {!Array<S|T>} A list of objects that are common to both arrays249* such that there is no common subsequence with size greater than the250* length of the list.251* @template S,T252*/253goog.math.longestCommonSubsequence = function(254array1, array2, opt_compareFn, opt_collectorFn) {255256var compare = opt_compareFn || function(a, b) { return a == b; };257258var collect = opt_collectorFn || function(i1, i2) { return array1[i1]; };259260var length1 = array1.length;261var length2 = array2.length;262263var arr = [];264for (var i = 0; i < length1 + 1; i++) {265arr[i] = [];266arr[i][0] = 0;267}268269for (var j = 0; j < length2 + 1; j++) {270arr[0][j] = 0;271}272273for (i = 1; i <= length1; i++) {274for (j = 1; j <= length2; j++) {275if (compare(array1[i - 1], array2[j - 1])) {276arr[i][j] = arr[i - 1][j - 1] + 1;277} else {278arr[i][j] = Math.max(arr[i - 1][j], arr[i][j - 1]);279}280}281}282283// Backtracking284var result = [];285var i = length1, j = length2;286while (i > 0 && j > 0) {287if (compare(array1[i - 1], array2[j - 1])) {288result.unshift(collect(i - 1, j - 1));289i--;290j--;291} else {292if (arr[i - 1][j] > arr[i][j - 1]) {293i--;294} else {295j--;296}297}298}299300return result;301};302303304/**305* Returns the sum of the arguments.306* @param {...number} var_args Numbers to add.307* @return {number} The sum of the arguments (0 if no arguments were provided,308* {@code NaN} if any of the arguments is not a valid number).309*/310goog.math.sum = function(var_args) {311return /** @type {number} */ (312goog.array.reduce(313arguments, function(sum, value) { return sum + value; }, 0));314};315316317/**318* Returns the arithmetic mean of the arguments.319* @param {...number} var_args Numbers to average.320* @return {number} The average of the arguments ({@code NaN} if no arguments321* were provided or any of the arguments is not a valid number).322*/323goog.math.average = function(var_args) {324return goog.math.sum.apply(null, arguments) / arguments.length;325};326327328/**329* Returns the unbiased sample variance of the arguments. For a definition,330* see e.g. http://en.wikipedia.org/wiki/Variance331* @param {...number} var_args Number samples to analyze.332* @return {number} The unbiased sample variance of the arguments (0 if fewer333* than two samples were provided, or {@code NaN} if any of the samples is334* not a valid number).335*/336goog.math.sampleVariance = function(var_args) {337var sampleSize = arguments.length;338if (sampleSize < 2) {339return 0;340}341342var mean = goog.math.average.apply(null, arguments);343var variance =344goog.math.sum.apply(null, goog.array.map(arguments, function(val) {345return Math.pow(val - mean, 2);346})) / (sampleSize - 1);347348return variance;349};350351352/**353* Returns the sample standard deviation of the arguments. For a definition of354* sample standard deviation, see e.g.355* http://en.wikipedia.org/wiki/Standard_deviation356* @param {...number} var_args Number samples to analyze.357* @return {number} The sample standard deviation of the arguments (0 if fewer358* than two samples were provided, or {@code NaN} if any of the samples is359* not a valid number).360*/361goog.math.standardDeviation = function(var_args) {362return Math.sqrt(goog.math.sampleVariance.apply(null, arguments));363};364365366/**367* Returns whether the supplied number represents an integer, i.e. that is has368* no fractional component. No range-checking is performed on the number.369* @param {number} num The number to test.370* @return {boolean} Whether {@code num} is an integer.371*/372goog.math.isInt = function(num) {373return isFinite(num) && num % 1 == 0;374};375376377/**378* Returns whether the supplied number is finite and not NaN.379* @param {number} num The number to test.380* @return {boolean} Whether {@code num} is a finite number.381* @deprecated Use {@link isFinite} instead.382*/383goog.math.isFiniteNumber = function(num) {384return isFinite(num);385};386387388/**389* @param {number} num The number to test.390* @return {boolean} Whether it is negative zero.391*/392goog.math.isNegativeZero = function(num) {393return num == 0 && 1 / num < 0;394};395396397/**398* Returns the precise value of floor(log10(num)).399* Simpler implementations didn't work because of floating point rounding400* errors. For example401* <ul>402* <li>Math.floor(Math.log(num) / Math.LN10) is off by one for num == 1e+3.403* <li>Math.floor(Math.log(num) * Math.LOG10E) is off by one for num == 1e+15.404* <li>Math.floor(Math.log10(num)) is off by one for num == 1e+15 - 1.405* </ul>406* @param {number} num A floating point number.407* @return {number} Its logarithm to base 10 rounded down to the nearest408* integer if num > 0. -Infinity if num == 0. NaN if num < 0.409*/410goog.math.log10Floor = function(num) {411if (num > 0) {412var x = Math.round(Math.log(num) * Math.LOG10E);413return x - (parseFloat('1e' + x) > num ? 1 : 0);414}415return num == 0 ? -Infinity : NaN;416};417418419/**420* A tweaked variant of {@code Math.floor} which tolerates if the passed number421* is infinitesimally smaller than the closest integer. It often happens with422* the results of floating point calculations because of the finite precision423* of the intermediate results. For example {@code Math.floor(Math.log(1000) /424* Math.LN10) == 2}, not 3 as one would expect.425* @param {number} num A number.426* @param {number=} opt_epsilon An infinitesimally small positive number, the427* rounding error to tolerate.428* @return {number} The largest integer less than or equal to {@code num}.429*/430goog.math.safeFloor = function(num, opt_epsilon) {431goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0);432return Math.floor(num + (opt_epsilon || 2e-15));433};434435436/**437* A tweaked variant of {@code Math.ceil}. See {@code goog.math.safeFloor} for438* details.439* @param {number} num A number.440* @param {number=} opt_epsilon An infinitesimally small positive number, the441* rounding error to tolerate.442* @return {number} The smallest integer greater than or equal to {@code num}.443*/444goog.math.safeCeil = function(num, opt_epsilon) {445goog.asserts.assert(!goog.isDef(opt_epsilon) || opt_epsilon > 0);446return Math.ceil(num - (opt_epsilon || 2e-15));447};448449450