Math
accumulate
const accumulate = (...nums) => nums.reduce((acc, n) => [...acc, n + +acc.slice(-1)], []);
accumulate(1, 2, 3, 4); // [1, 3, 6, 10]
accumulate(...[1, 2, 3, 4]); // [1, 3, 6, 10]
and
and(true, true); // true
and(true, false); // false
and(false, false); // false
approximatelyEqual
检查两个数字是否彼此近似相等。
const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;
approximatelyEqual(Math.PI / 2.0, 1.5708); // true
average
const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
average(...[1, 2, 3]); // 2
average(1, 2, 3); // 2
averageBy
const averageBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) / arr.length;
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5
averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5
binomialCoefficient
计算两个整数n和k的二项式系数。
const binomialCoefficient = (n, k) => {
if (Number.isNaN(n) || Number.isNaN(k)) return NaN;
if (k < 0 || k > n) return 0;
if (k === 0 || k === n) return 1;
if (k === 1 || k === n - 1) return n;
if (n - k < k) k = n - k;
let res = n;
for (let j = 2; j <= k; j++) res *= (n - j + 1) / j;
return Math.round(res);
};
binomialCoefficient(8, 2); // 28
celsiusToFahrenheit
将摄氏温度转换为华氏温度。
const celsiusToFahrenheit = degrees => 1.8 * degrees + 32;
celsiusToFahrenheit(33); // 91.4
clampNumber
const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
clampNumber(2, 3, 5); // 3
clampNumber(1, -1, -5); // -1
degreesToRads
将角度转换为弧度。
const degreesToRads = deg => (deg * Math.PI) / 180.0;
degreesToRads(90.0); // ~1.5708
digitize
将数字转换为数字数组。
const digitize = n => String(n).split('').map(i => parseInt(i));
// or
const digitize = n => [...String(n)].map(i => parseInt(i));
// or
const digitize = n => [...`${n}`].map(i => parseInt(i));
digitize(123); // [1, 2, 3]
distance
返回两点之间的距离。
const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
distance(1, 1, 2, 3); // 2.23606797749979
elo
const elo = ([...ratings], kFactor = 32, selfRating) => {
const [a, b] = ratings;
const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400));
const newRating = (rating, i) =>
(selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a));
if (ratings.length === 2) return [newRating(a, 1), newRating(b, 0)];
for (let i = 0, len = ratings.length; i < len; i++) {
let j = i;
while (j < len - 1) {
j++;
[ratings[i], ratings[j]] = elo([ratings[i], ratings[j]], kFactor);
}
}
return ratings;
};
// Standard 1v1s
elo([1200, 1200]); // [1216, 1184]
elo([1200, 1200], 64); // [1232, 1168]
// 4 player FFA, all same rank
elo([1200, 1200, 1200, 1200]).map(Math.round); // [1246, 1215, 1185, 1154]
/*
For teams, each rating can adjusted based on own team's average rating vs.
average rating of opposing team, with the score being added to their
own individual rating by supplying it as the third argument.
*/
factorial
阶乘
const factorial = n =>
n < 0
? (() => {
throw new TypeError('Negative numbers are not allowed!');
})()
: n <= 1
? 1
: n * factorial(n - 1);
factorial(6); // 720
fahrenheitToCelsius
将华氏温度转换为摄氏温度。
const fahrenheitToCelsius = degrees => ((degrees - 32) * 5) / 9;
fahrenheitToCelsius(32); // 0
fibonacci
const fibonacci = n =>
Array.from({ length: n }).reduce(
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
[]
);
fibonacci(6); // [0, 1, 1, 2, 3, 5]
gcd
计算两个或多个数字/数组之间的最大公约数。
const gcd = (...arr) => {
const _gcd = (x, y) => (!y ? x : gcd(y, x % y));
return [...arr].reduce((a, b) => _gcd(a, b));
};
gcd(8, 36); // 4
gcd(...[12, 8, 32]); // 4
geometricProgression
const geometricProgression = (end, start = 1, step = 2) =>
Array.from({ length: Math.floor(Math.log(end / start) / Math.log(step)) + 1 }).map(
(v, i) => start * step ** i
);
geometricProgression(256); // [1, 2, 4, 8, 16, 32, 64, 128, 256]
geometricProgression(256, 3); // [3, 6, 12, 24, 48, 96, 192]
geometricProgression(256, 1, 4); // [1, 4, 16, 64, 256]
hammingDistance
汉明距离度量了通过替换字符的方式将字符串x变成y所需要的最小的替换次数。
// 举例说明以下字符串间的汉明距离为:
// "karolin" and "kathrin" is 3.
// "karolin" and "kerstin" is 3.
// 1011101 and 1001001 is 2.
// 2173896 and 2233796 is 3.
const hammingDistance = (num1, num2) => ((num1 ^ num2).toString(2).match(/1/g) || '').length;
hammingDistance(2, 3); // 1
inRange
// end未赋值则从0开始
const inRange = (n, start, end = null) => {
if (end && start > end) [end, start] = [start, end];
return end == null ? n >= 0 && n < start : n >= start && n < end;
};
inRange(3, 2, 5); // true
inRange(3, 4); // true
inRange(2, 3, 5); // false
inRange(3, 2); // false
isDivisible
检查第一个数字参数是否可被第二个参数整除。
const isDivisible = (dividend, divisor) => dividend % divisor === 0;
isDivisible(6, 3); // true
isEven
const isEven = num => num % 2 === 0;
isEven(3); // false
isNegativeZero
检查给定值是否等于负零(-0)。
const isNegativeZero = val => val === 0 && 1 / val === -Infinity;
isNegativeZero(-0); // true
isNegativeZero(0); // false
isOdd
const isOdd = num => num % 2 === 1;
isOdd(3); // true
isPowerOfTwo
如果给定数字为2的幂,则返回true,否则返回false。
const isPowerOfTwo = n => !!n && (n & (n - 1)) == 0;
isPowerOfTwo(0); // false
isPowerOfTwo(1); // true
isPowerOfTwo(8); // true
isPrime
检查提供的整数是否为质数。
const isPrime = num => {
const boundary = Math.floor(Math.sqrt(num));
for (var i = 2; i <= boundary; i++) if (num % i === 0) return false;
return num >= 2;
};
isPrime(11); // true
lcm
返回两个或多个数字的最小公倍数。
const lcm = (...arr) => {
const gcd = (x, y) => (!y ? x : gcd(y, x % y));
const _lcm = (x, y) => (x * y) / gcd(x, y);
return [...arr].reduce((a, b) => _lcm(a, b));
};
lcm(12, 7); // 84
lcm(...[1, 3, 4, 5]); // 60
luhnCheck
Luhn算法
const luhnCheck = num => {
let arr = (num + '')
.split('')
.reverse()
.map(x => parseInt(x));
let lastDigit = arr.splice(0, 1)[0];
let sum = arr.reduce((acc, val, i) => (i % 2 !== 0 ? acc + val : acc + ((val * 2) % 9) || 9), 0);
sum += lastDigit;
return sum % 10 === 0;
};
luhnCheck('4485275742308327'); // true
luhnCheck(6011329933655299); // false
luhnCheck(123456789); // false
mapNumRange
const mapNumRange = (num, inMin, inMax, outMin, outMax) =>
((num - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin;
mapNumRange(5, 0, 10, 0, 100); // 50
maxBy
const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
maxBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 8
maxBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 8
median
返回数字数组的中位数。
const median = arr => {
const mid = Math.floor(arr.length / 2),
nums = [...arr].sort((a, b) => a - b);
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
};
median([5, 6, 50, 1, -5]); // 5
midpoint
计算两对(x,y)点之间的中点。
const midpoint = ([x1, y1], [x2, y2]) => [(x1 + x2) / 2, (y1 + y2) / 2];
midpoint([2, 2], [4, 4]); // [3, 3]
midpoint([4, 4], [6, 6]); // [5, 5]
midpoint([1, 3], [2, 4]); // [1.5, 3.5]
minBy
const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
minBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 2
minBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 2
not
const not = a => !a;
not(true); // false
not(false); // true
or
const or = (a, b) => a || b;
or(true, true); // true
or(true, false); // true
or(false, false); // false
percentile
使用百分比公式来计算给定数组中有多少个数字小于或等于给定值。
const percentile = (arr, val) =>
(100 * arr.reduce((acc, v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0), 0)) / arr.length;
percentile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 6); // 55
powerset
返回给定数字数组的幂集。
const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
powerset([1, 2]); // [[], [1], [2], [2, 1]]
primes
质数
const primes = num => {
let arr = Array.from({ length: num - 1 }).map((x, i) => i + 2),
sqroot = Math.floor(Math.sqrt(num)),
numsTillSqroot = Array.from({ length: sqroot - 1 }).map((x, i) => i + 2);
numsTillSqroot.forEach(x => (arr = arr.filter(y => y % x !== 0 || y === x)));
return arr;
};
primes(10); // [2,3,5,7]
radsToDegrees
将角度从弧度转换为度。
const radsToDegrees = rad => (rad * 180.0) / Math.PI;
radsToDegrees(Math.PI / 2); // 90
randomHexColorCode
生成随机的十六进制颜色代码。
const randomHexColorCode = () => {
let n = (Math.random() * 0xfffff * 1000000).toString(16);
return '#' + n.slice(0, 6);
};
randomHexColorCode(); // "#e34155"
randomIntArrayInRange
const randomIntArrayInRange = (min, max, n = 1) =>
Array.from({ length: n }, () => Math.floor(Math.random() * (max - min + 1)) + min);
randomIntArrayInRange(12, 35, 10); // [ 34, 14, 27, 17, 30, 27, 20, 26, 21, 14 ]
randomIntegerInRange
const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
randomIntegerInRange(0, 5); // 2
randomNumberInRange
const randomNumberInRange = (min, max) => Math.random() * (max - min) + min;
randomNumberInRange(2, 10); // 6.0211363285087005
round
// Number(`${Math.round(1.005e2)}e-2`)
const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
round(1.005, 2); // 1.01
sdbm
将输入字符串哈希为整数。
const sdbm = str => {
let arr = str.split('');
return arr.reduce(
(hashCode, currentVal) =>
(hashCode = currentVal.charCodeAt(0) + (hashCode << 6) + (hashCode << 16) - hashCode),
0
);
}
sdbm('name'); // -3521204949
standardDeviation
返回数字数组的标准差。
const standardDeviation = (arr, usePopulation = false) => {
const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length;
return Math.sqrt(
arr.reduce((acc, val) => acc.concat((val - mean) ** 2), []).reduce((acc, val) => acc + val, 0) /
(arr.length - (usePopulation ? 0 : 1))
);
};
standardDeviation([10, 2, 38, 23, 38, 23, 21]); // 13.284434142114991 (sample)
standardDeviation([10, 2, 38, 23, 38, 23, 21], true); // 12.29899614287479 (population)
sum
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
sum(1, 2, 3, 4); // 10
sum(...[1, 2, 3, 4]); // 10
sumBy
const sumBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0);
sumBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 20
sumBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 20
sumPower
返回从开始到结束(包括两端)的所有数字的幂的和。
const sumPower = (end, power = 2, start = 1) =>
Array(end + 1 - start)
.fill(0)
.map((x, i) => (i + start) ** power)
.reduce((a, b) => a + b, 0);
sumPower(10); // 385
sumPower(10, 3); // 3025
sumPower(10, 3, 5); // 2925
toCurrency
取一个数字并返回指定的货币格式。
Intl.NumberFormat
是对语言敏感的格式化数字类的构造器类
const toCurrency = (n, curr, LanguageFormat = undefined) =>
Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n);
toCurrency(123456.789, 'EUR'); // €123,456.79 | currency: Euro | currencyLangFormat: Local
toCurrency(123456.789, 'USD', 'en-us'); // $123,456.79 | currency: US Dollar | currencyLangFormat: English (United States)
toCurrency(123456.789, 'USD', 'fa'); // ۱۲۳٬۴۵۶٫۷۹ $ | currency: US Dollar | currencyLangFormat: Farsi
toCurrency(322342436423.2435, 'JPY'); // ¥322,342,436,423 | currency: Japanese Yen | currencyLangFormat: Local
toCurrency(322342436423.2435, 'JPY', 'fi'); // 322 342 436 423 ¥ | currency: Japanese Yen | currencyLangFormat: Finnish
toDecimalMark
将数字转换为小数点格式的字符串。
const toDecimalMark = num => num.toLocaleString('en-US');
toDecimalMark(12305030388.9087); // "12,305,030,388.909"
toOrdinalSuffix
在数字后添加序数后缀。
const toOrdinalSuffix = num => {
const int = parseInt(num),
digits = [int % 10, int % 100],
ordinals = ['st', 'nd', 'rd', 'th'],
oPattern = [1, 2, 3, 4],
tPattern = [11, 12, 13, 14, 15, 16, 17, 18, 19];
return oPattern.includes(digits[0]) && !tPattern.includes(digits[1])
? int + ordinals[digits[0] - 1]
: int + ordinals[3];
};
toOrdinalSuffix('123'); // "123rd"
toSafeInteger
const toSafeInteger = num =>
Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER));
toSafeInteger('3.2'); // 3
toSafeInteger(Infinity); // 9007199254740991
validateNumber
const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
validateNumber('10'); // true
vectorAngle
返回两个向量之间的角度(θ)。
const vectorAngle = (x, y) => {
let mX = Math.sqrt(x.reduce((acc, n) => acc + Math.pow(n, 2), 0));
let mY = Math.sqrt(y.reduce((acc, n) => acc + Math.pow(n, 2), 0));
return Math.acos(x.reduce((acc, n, i) => acc + n * y[i], 0) / (mX * mY));
};
vectorAngle([3, 4], [4, 3]); // 0.283794109208328
vectorDistance
返回两个向量之间的距离。
const vectorDistance = (x, y) =>
Math.sqrt(x.reduce((acc, val, i) => acc + Math.pow(val - y[i], 2), 0));
vectorDistance([10, 0, 5], [20, 0, 10]); // 11.180339887498949
文档信息
- 本文作者:Jian Li
- 本文链接:https://ifwechat.com//wiki/javascript-math/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)