СЦБИСТ - сайт железнодорожников №1
Это сообщение показано отдельно, перейти в тему, где размещено сообщение: Функция вычисления факториала node.js
Старый 03.07.2018, 10:40   #1 (ссылка)
Crow indian
 
Аватар для Admin

Регистрация: 21.02.2009
Возраст: 41
Сообщений: 30,469
Поблагодарил: 398 раз(а)
Поблагодарили 6056 раз(а)
Фотоальбомы: 2624 фото
Записей в дневнике: 911
Репутация: 126141

Тема: Функция вычисления факториала 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).
Admin вне форума   Цитировать 14
 Нажмите здесь, чтобы написать комментарий к этому сообщению  
 

Яндекс.Метрика