Функция вычисления факториала node.js
В Node.js есть несколько способов реализации функции вычисления факториала. Рассмотрю все варианты — от простого до оптимизированного.
1. Итеративный способ (рекомендуемый)
Самый эффективный и безопасный способ:
PHP код:
function factorialIterative(n) {
if (n < 0) throw new Error('Факториал определён только для неотрицательных чисел');
if (n === 0 || n === 1) return 1;
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
}
// Использование
console.log(factorialIterative(5)); // 120
console.log(factorialIterative(10)); // 3628800
2. Рекурсивный способ
Классический, но с ограничениями:
Ограничение: для больших n (> 10000) может вызвать переполнение стека.
PHP код:
function factorialRecursive(n) {
if (n < 0) throw new Error('Факториал определён только для неотрицательных чисел');
if (n === 0 || n === 1) return 1;
return n * factorialRecursive(n - 1);
}
// Использование
console.log(factorialRecursive(5)); // 120
3. Оптимизированный рекурсивный (хвостовая рекурсия)
PHP код:
function factorialTailRecursive(n, accumulator = 1) {
if (n < 0) throw new Error('Факториал определён только для неотрицательных чисел');
if (n === 0 || n === 1) return accumulator;
return factorialTailRecursive(n - 1, n * accumulator);
}
// Использование
console.log(factorialTailRecursive(5)); // 120
4. С использованием BigInt (для очень больших чисел)
PHP код:
function factorialBigInt(n) {
if (n < 0) throw new Error('Факториал определён только для неотрицательных чисел');
if (n === 0 || n === 1) return 1n;
let result = 1n;
for (let i = 2n; i <= n; i++) {
result *= i;
}
return result;
}
// Использование
console.log(factorialBigInt(20)); // 2432902008176640000n
console.log(factorialBigInt(50).toString()); // Огромное число
5. С мемоизацией (кэширование результатов)
PHP код:
const factorialMemo = (function() {
const cache = { 0: 1, 1: 1 };
return function factorial(n) {
if (n < 0) throw new Error('Факториал определён только для неотрицательных чисел');
if (cache[n] !== undefined) return cache[n];
cache[n] = n * factorial(n - 1);
return cache[n];
};
})();
// Использование
console.log(factorialMemo(5)); // 120 (вычисляется)
console.log(factorialMemo(5)); // 120 (берётся из кэша)
console.log(factorialMemo(6)); // 720 (использует кэшированный 5!)
6. Асинхронная версия (для неблокирующих операций)
PHP код:
async function factorialAsync(n) {
if (n < 0) throw new Error('Факториал определён только для неотрицательных чисел');
if (n === 0 || n === 1) return 1;
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
// Периодически уступаем управление для других операций
if (i % 1000 === 0) {
await new Promise(resolve => setImmediate(resolve));
}
}
return result;
}
// Использование
(async () => {
console.log(await factorialAsync(5)); // 120
})();
7. С обработкой ошибок и валидацией
PHP код:
function factorialSafe(n) {
// Проверка типа
if (!Number.isInteger(n)) {
throw new TypeError('Аргумент должен быть целым числом');
}
// Проверка на отрицательное значение
if (n < 0) {
throw new RangeError('Факториал определён только для неотрицательных чисел');
}
// Проверка на слишком большое число
if (n > 170) {
throw new RangeError('Результат выходит за пределы Number.MAX_SAFE_INTEGER');
}
if (n === 0 || n === 1) return 1;
let result = 1;
for (let i = 2; i <= n; i++) {
result *= i;
}
return result;
}
Сравнение производительности
PHP код:
const n = 100;
console.time('Итеративный');
factorialIterative(n);
console.timeEnd('Итеративный');
console.time('Рекурсивный');
factorialRecursive(n);
console.timeEnd('Рекурсивный');
console.time('Мемоизация');
factorialMemo(n);
console.timeEnd('Мемоизация');
Рекомендации:
Для большинства случаев используйте итеративный способ — он быстрый и безопасный
Для больших чисел (> 170) используйте BigInt
Для многократных вычислений используйте мемоизацию
Для академических целей подойдёт рекурсивный способ
В production всегда добавляйте валидацию входных данных
Помните, что факториал быстро растёт: 20! ≈ 2.43e18, что уже превышает безопасный предел для Number в JavaScript (2^53 - 1).
|