Как посчитать факториал 100 без калькулятора
Перейти к содержимому

Как посчитать факториал 100 без калькулятора

  • автор:

Вычисление факториала

Факториалом числа называют произведение всех натуральных чисел до него включительно. Например, факториал числа 5 равен произведению 1 * 2 * 3 * 4 * 5 = 120.

Формула нахождения факториала:

n! = 1 * 2 * … * n,

где n – это число, а n! – факториал этого числа.

Формулу можно представить в таком виде:

n! = 1 * … * (n-2) * (n-1) * n,

т. е. каждый предыдущий множитель меньше на единицу, чем последующий. Или в перевернутом виде, когда каждый следующий меньше предыдущего на единицу:

n! = n * (n-1) * (n-2) * … * 1,

Для вычисления факториала с помощью цикла можно использовать любую формулу. Для рекурсивного вычисления используется вторая.

Вычисление факториала с помощью циклов

С помощь цикла while :

n = int(input()) factorial = 1 while n > 1: factorial *= n n -= 1 print(factorial)

Вычисление факториала с помощью цикла for :

n = int(input()) factorial = 1 for i in range(2, n+1): factorial *= i print(factorial)

Нахождение факториала рекурсией

def fac(n): if n == 1: return 1 return fac(n - 1) * n print(fac(5))

Поток выполнения программы при n = 5:

  1. Вызов функции fac(5)
  2. fac(5) вызывает fac(4)
  3. fac(4) вызывает fac(3)
  4. fac(3) вызывает fac(2)
  5. fac(2) вызывает fac(1)
  6. fac(1) возвращает в fac(2) число 1
  7. fac(2) возвращает в fac(3) число 1 * 2, т. е. 2
  8. fac(3) возвращает в fac(4) число 2 * 3, т. е. 6
  9. fac(4) возвращает в fac(5) число 6 * 4, т. е. 24
  10. fac(5) возвращает число 24 * 5, т. е. 120 в основную ветку программы
  11. Число 120 выводится на экран

Функция factorial модуля math

Модуль math языка программирования Python содержит функцию factorial , принимающую в качестве аргумента неотрицательное целое число и возвращающую факториал этого числа:

>>> import math >>> math.factorial(4) 24

X Скрыть Наверх

Решение задач на Python

Алгоритмы быстрого вычисления факториала

Понятие факториала известно всем. Это функция, вычисляющая произведение последовательных натуральных чисел от 1 до N включительно: N! = 1 * 2 * 3 *… * N. Факториал — быстрорастущая функция, уже для небольших значений N значение N! имеет много значащих цифр.

Попробуем реализовать эту функцию на языке программирования. Очевидно, нам понадобиться язык, поддерживающий длинную арифметику. Я воспользуюсь C#, но с таким же успехом можно взять Java или Python.

Наивный алгоритм

Итак, простейшая реализация (назовем ее наивной) получается прямо из определения факториала:

static BigInteger FactNaive(int n)

На моей машине эта реализация работает примерно 1,6 секунд для N=50 000.

Далее рассмотрим алгоритмы, которые работают намного быстрее наивной реализации.

Алгоритм вычисления деревом

Первый алгоритм основан на том соображении, что длинные числа примерно одинаковой длины умножать эффективнее, чем длинное число умножать на короткое (как в наивной реализации). То есть нам нужно добиться, чтобы при вычислении факториала множители постоянно были примерно одинаковой длины.

Пусть нам нужно найти произведение последовательных чисел от L до R, обозначим его как P(L, R). Разделим интервал от L до R пополам и посчитаем P(L, R) как P(L, M) * P(M + 1, R), где M находится посередине между L и R, M = (L + R) / 2. Заметим, что множители будут примерно одинаковой длины. Аналогично разобьем P(L, M) и P(M + 1, R). Будем производить эту операцию, пока в каждом интервале останется не более двух множителей. Очевидно, что P(L, R) = L, если L и R равны, и P(L, R) = L * R, если L и R отличаются на единицу. Чтобы найти N! нужно посчитать P(2, N).

Посмотрим, как будет работать наш алгоритм для N=10, найдем P(2, 10):

P(2, 10)
P(2, 6) * P(7, 10)
( P(2, 4) * P(5, 6) ) * ( P(7, 8) * P(9, 10) )
( (P(2, 3) * P(4) ) * P(5, 6) ) * ( P(7, 8) * P(9, 10) )
( ( (2 * 3) * (4) ) * (5 * 6) ) * ( (7 * 8) * (9 * 10) )
( ( 6 * 4 ) * 30 ) * ( 56 * 90 )
( 24 * 30 ) * ( 5 040 )
720 * 5 040
3 628 800

Дерево вычисления факториала

Получается своеобразное дерево, где множители находятся в узлах, а результат получается в корне

Реализуем описанный алгоритм:

static BigInteger ProdTree(int l, int r) < if (l >r) return 1; if (l == r) return l; if (r - l == 1) return (BigInteger)l * r; int m = (l + r) / 2; return ProdTree(l, m) * ProdTree(m + 1, r); > static BigInteger FactTree(int n)

Для N=50 000 факториал вычисляется за 0,9 секунд, что почти вдвое быстрее, чем в наивной реализации.

Алгоритм вычисления факторизацией

Второй алгоритм быстрого вычисления использует разложение факториала на простые множители (факторизацию). Очевидно, что в разложении N! участвуют только простые множители от 2 до N. Попробуем посчитать, сколько раз простой множитель K содержится в N!, то есть узнаем степень множителя K в разложении. Каждый K-ый член произведения 1 * 2 * 3 *… * N увеличивает показатель на единицу, то есть показатель степени будет равен N / K. Но каждый K 2 -ый член увеличивает степень еще на единицу, то есть показатель становится N / K + N / K 2 . Аналогично для K 3 , K 4 и так далее. В итоге получим, что показатель степени при простом множителе K будет равен N / K + N / K 2 + N / K 3 + N / K 4 +…

Для наглядности посчитаем, сколько раз двойка содержится в 10! Двойку дает каждый второй множитель (2, 4, 6, 8 и 10), всего таких множителей 10 / 2 = 5. Каждый четвертый дает четверку (2 2 ), всего таких множителей 10 / 4 = 2 (4 и 8). Каждый восьмой дает восьмерку (2 3 ), такой множитель всего один 10 / 8 = 1 (8). Шестнадцать (2 4 ) и более уже не дает ни один множитель, значит, подсчет можно завершать. Суммируя, получим, что показатель степени при двойке в разложении 10! на простые множители будет равен 10 / 2 + 10 / 4 + 10 / 8 = 5 + 2 + 1 = 8.

Если действовать таким же образом, можно найти показатели при 3, 5 и 7 в разложении 10!, после чего остается только вычислить значение произведения:

10! = 2 8 * 3 4 * 5 2 * 7 1 = 3 628 800

Осталось найти простые числа от 2 до N, для этого можно использовать решето Эратосфена:

static BigInteger FactFactor(int n) < if (n < 0) return 0; if (n == 0) return 1; if (n == 1 || n == 2) return n; bool[] u = new bool[n + 1]; // маркеры для решета Эратосфена List> p = new List>(); // множители и их показатели степеней for (int i = 2; i 0) < c += k; k /= i; >// запоминаем множитель и его показатель степени p.Add(new Tuple(i, c)); // просеиваем составные числа через решето int j = 2; while (i * j > // вычисляем факториал BigInteger r = 1; for (int i = p.Count() - 1; i >= 0; --i) r *= BigInteger.Pow(p[i].Item1, p[i].Item2); return r; > 

Эта реализация также тратит примерно 0,9 секунд на вычисление 50 000!

Библиотека GMP

Как справедливо отметил pomme скорость вычисления факториала на 98% зависит от скорости умножения. Попробуем протестировать наши алгоритмы, реализовав их на C++ с использованием библиотеки GMP. Результаты тестирования приведены ниже, по ним получается что алгоритм умножения в C# имеет довольно странную асимптотику, поэтому оптимизация дает относительно небольшой выигрыш в C# и огромный в C++ с GMP. Однако этому вопросу вероятно стоит посвятить отдельную статью.

Сравнение производительности

Таблица результатов

Все алгоритмы тестировались для N равном 1 000, 2 000, 5 000, 10 000, 20 000, 50 000 и 100 000 десятью итерациями. В таблице указано среднее значение времени работы в миллисекундах.

График с линейной шкалой

График с линейной шкалой

График с логарифмической шкалой

График с логарифмической шкалой

Идеи и алгоритмы из комментариев

Хабражители предложили немало интересных идей и алгоритмов в ответ на мою статью, здесь я оставлю ссылки на лучшие из них

Исходные коды

Исходные коды реализованных алгоритмов приведены под спойлерами

using System; using System.Linq; using System.Text; using System.Numerics; using System.Collections.Generic; using System.Collections.Specialized; namespace BigInt < class Program < static BigInteger FactNaive(int n) < BigInteger r = 1; for (int i = 2; i static BigInteger ProdTree(int l, int r) < if (l >r) return 1; if (l == r) return l; if (r - l == 1) return (BigInteger)l * r; int m = (l + r) / 2; return ProdTree(l, m) * ProdTree(m + 1, r); > static BigInteger FactTree(int n) < if (n < 0) return 0; if (n == 0) return 1; if (n == 1 || n == 2) return n; return ProdTree(2, n); >static BigInteger FactFactor(int n) < if (n < 0) return 0; if (n == 0) return 1; if (n == 1 || n == 2) return n; bool[] u = new bool[n + 1]; List> p = new List>(); for (int i = 2; i 0) < c += k; k /= i; >p.Add(new Tuple(i, c)); int j = 2; while (i * j > BigInteger r = 1; for (int i = p.Count() - 1; i >= 0; --i) r *= BigInteger.Pow(p[i].Item1, p[i].Item2); return r; > static void Main(string[] args) < int n; int t; Console.Write("n = "); n = Convert.ToInt32(Console.ReadLine()); t = Environment.TickCount; BigInteger fn = FactNaive(n); Console.WriteLine("Naive time: ms", Environment.TickCount - t); t = Environment.TickCount; BigInteger ft = FactTree(n); Console.WriteLine("Tree time: ms", Environment.TickCount - t); t = Environment.TickCount; BigInteger ff = FactFactor(n); Console.WriteLine("Factor time: ms", Environment.TickCount - t); Console.WriteLine("Check: ", fn == ft && ft == ff ? "ok" : "fail"); > > > 

C++ с GMP

#include #include #include #include #include using namespace std; mpz_class FactNaive(int n) < mpz_class r = 1; for (int i = 2; i mpz_class ProdTree(int l, int r) < if (l >r) return 1; if (l == r) return l; if (r - l == 1) return (mpz_class)r * l; int m = (l + r) / 2; return ProdTree(l, m) * ProdTree(m + 1, r); > mpz_class FactTree(int n) < if (n < 0) return 0; if (n == 0) return 1; if (n == 1 || n == 2) return n; return ProdTree(2, n); >mpz_class FactFactor(int n) < if (n < 0) return 0; if (n == 0) return 1; if (n == 1 || n == 2) return n; vectoru(n + 1, false); vector > p; for (int i = 2; i 0) < c += k; k /= i; >p.push_back(make_pair(i, c)); int j = 2; while (i * j > mpz_class r = 1; for (int i = p.size() - 1; i >= 0; --i) < mpz_class w; mpz_pow_ui(w.get_mpz_t(), mpz_class(p[i].first).get_mpz_t(), p[i].second); r *= w; >return r; > mpz_class FactNative(int n) < mpz_class r; mpz_fac_ui(r.get_mpz_t(), n); return r; >int main() < int n; unsigned int t; cout 


  • длинная арифметика
  • факториал
  • оптимизация

Как найти факториал

Как найти факториал

Факториалом натурального числа N (обозначается N!) называется произведение всех натуральных чисел, не превышающих N. Найти факториал числа для небольших значений N сравнительно просто. Однако с ростом N сложность расчетов (на основе определения) значительно возрастает. Поэтому найти факториал большого числа без вычислительной техники практически невозможно.Вам понадобится

Для того чтобы посчитать факториал числа, возьмите инженерный калькулятор. Наберите на клавиатуре калькулятора исходное число и нажмите кнопку вычисления факториала. В зависимости от конструкции калькулятора, надпись на этой кнопке может выглядеть по-разному. Например, «х!», «N!» или «n!». Однако в любом случае, в обозначении факториала должен присутствовать восклицательный знак («!»).

Так как значение факториала числа очень быстро увеличивается по мере возрастания аргумента, то начиная с 15-ти, значение факториала занимает более 12-ти знаков и перестает умещаться на индикаторах обычных калькуляторов. Как только результат вычислений превысит разрядность калькулятора, большинство из них переходит в «экспоненциальный» режим отображения чисел. Так, например, факториал 100 будет представлен в виде: 9,3326215443944152681699238856267e+157 (или аналогичном). Чтобы получить результат в более привычной форме, припишите к числу, расположенному до символа «е» («Е»), столько нулей, сколько указано после буквы «е».

Чтобы найти факториал числа при помощи компьютера, запустите программу «калькулятор». Для этого достаточно нажать на кнопки «Пуск», «Выполнить», набрать «calc» и нажать «Ок». Проверьте в каком режиме загрузилась программа «Калькулятор». Если окно программы напоминает обыкновенный «бухгалтерский» калькулятор, то переключите его в режим «инженерных» расчетов. Для этого щелкните мышкой на пункте меню «Вид», а затем выберите в выпавшем списке строку «Инженерный». Далее проделайте те же шаги, которые указаны в предыдущем пункте инструкции. То есть введите само число и нажмите кнопку, обозначенную как «n!».

Если вам приходится регулярно вычислять факториалы, а инженерного калькулятора или компьютера поблизости не оказывается, то просто распечатайте представленную ниже таблицу. Используя ее, вы сможете без труда и использования вычислительной техники найти факториал любого числа – от 0 до 50-ти.

Что такое факториал и как его вычислить

Статья, после которой вы начнёте щёлкать факториалы как орешки.

Иллюстрация: Катя Павловская для Skillbox Media

Дмитрий Зверев

Дмитрий Зверев

Любитель научной фантастики и технологического прогресса. Хорошо сочетает в себе заумного технаря и утончённого гуманитария. Пишет про IT и радуется этому.

Даже если вы уже давно окончили школу, факториалы всё равно могут доставить немало приятных флешбэков — например, если вы обучаетесь программированию и знакомитесь с задачками на рекурсию или комбинаторику. Поэтому мы решили максимально просто объяснить, что такое факториал, как его вычислять и зачем он вообще нужен.

Эта статья будет полезна как опытным программистам, которые хотят освежить знания, так и тем, кто ещё учится: школьникам, студентам и совсем зелёным джунам.

Что такое факториал

Факториал числа n — это произведение всех натуральных чисел от единицы до n. Обозначается факториал символом восклицательного знака: !.

Это определение из учебника, и оно пока звучит сложновато — неясно, зачем эти факториалы вообще нужны и как они могут пригодиться в науке и технике. Но об этом чуть позже — для начала давайте посмотрим на примеры факториалов:

Чтобы вычислить их, нам нужно перемножить все числа от единицы до числа, стоящего под знаком факториала — так гласит определение. Получаем выражения:

Ещё в математическом определении сказано, что факториал не может быть отрицательным или дробным — то есть вот такие факториалы вычислить нельзя:

Для чего нужен факториал

Факториалы незаменимы там, где нужно быстро посчитать количество комбинаций и сочетаний разных предметов. В математике этому посвящён даже целый раздел — комбинаторика. Её методы используют много где: от лингвистики до криптографии и анализа ДНК. И во всех этих сферах факториал помогает упрощать сложные вычисления.

Разберём на примере, как это работает.

Допустим, у вас есть пять шоколадок и вы решили раздать их пяти друзьям — каждому по одной. Задача — выяснить, сколько существует способов раздать эти шоколадки. Начинаем размышлять:

  • первую шоколадку можно отдать одному из пяти друзей;
  • вторую — одному из четырёх друзей, потому что один уже получил свою шоколадку;
  • третью — одному из трёх, потому что двое уже наслаждаются своими шоколадками;
  • четвёртую — одному из двух;
  • пятую — последнему другу.

Получается, что способов раздать первую шоколадку — 5, вторую — 4, третью — 3, четвёртую — 2, а пятую — всего 1. По правилам математики, чтобы выяснить общее количество всех вариантов, нужно перемножить их между собой. Ну а кто мы такие, чтобы с этими правилами спорить?

Смотрим на выражение выше и понимаем: ведь оно идеально вписывается в определение факториала — произведение натуральных чисел от одного до n (в нашем случае n равно 5). Следовательно, это выражение можно коротко и изящно записать в виде факториала:

Выходит, что всего способов раздать пять шоколадок пяти друзьям существует 120. Вот как может выглядеть один из них:

Конечно, в жизни вам вряд ли придётся считать количество способов раздать друзьям шоколадки. Но, например, в статистике, теории вероятностей, матанализе и программировании факториалы используют сплошь и рядом. Так что, если видите себя в будущем на матмехе или, на худой конец, в IT, то лучше познакомиться с ними хотя бы бегло.

Какие свойства и формулы есть у факториалов

Так как факториалы используются в разных областях математики, свойств у них довольно много — каждая область привносит какие-то свои методы вычислений. Одно из свойств вы уже знаете: факториал — это всегда целое положительное число. Вот ещё несколько, которые стоит запомнить:

  • Факториал нуля равен единице — 0! = 1.
  • Факториал единицы тоже равен единице: 1! = 1.
  • Рекурсия: n! = (n – 1)! × n. Это основное свойство факториалов, о нём мы чуть подробнее поговорим дальше.

Мы видим, что каждое свойство описывается какой-то формулой — и некоторые из этих формул могут быть весьма полезны. Они позволяют нам находить факториалы проще и быстрее, чем простым перемножением натуральных чисел. Разберём эти формулы тоже.

Формула Стирлинга

Чтобы вычислить факториал, не используя так много операций умножения, придумали формулу Стирлинга. Вот как она выглядит:

Выглядит страшно, но на самом деле она очень полезная. Её используют, когда хотят приблизительно узнать факториал большого числа. Обычным способом это будет сделать сложно даже мощному компьютеру — например, попробуйте посчитать в онлайн-калькуляторе факториал числа 10 024 (спойлер: это может занять несколько часов и даже дней).

Давайте попробуем вычислить факториал числа 6 по этой формуле:

Число e примерно равно 2,71, а π — 3,14. Подставляем их в выражение и получаем ответ:

Получили приближённое значение настоящего факториала, который равен 720. Но можно сделать ответ и более точным. Для этого нужно добавить больше знаков после запятой всем переменным — например, если взять 20 знаков, то ответ будет таким:

Это уже больше похоже на правду. Хотя погрешность всё равно есть.

Рекуррентная формула

Рекуррентная формула позволяет вычислить факториал числа n, основываясь на факториале предыдущего числа — (n – 1). Выглядит она так:

В целом рекуррентная формула не приносит нам большой пользы, так как всё равно приходится вычислять факториал предыдущего числа. Если он равен какому-то большому числу (например, 100), то использование формулы теряет смысл — слишком уж много вычислений это потребует.

Рекуррентная формула основана на главном свойстве факториалов — рекурсии: n! = (n – 1)! × n. Это свойство особенно полезно при решении задач по комбинаторике: так мы можем быстро сокращать факториалы и упрощать выражения.

Однако рекуррентная формула хорошо подходит для алгоритмов — в частности, для программирования. Мы можем задать начальное значение: например, что 0! = 1 или 1! = 1, а затем считать следующие факториалы по формуле:

Получим алгоритм для вычисления факториалов. Не очень эффективный, но простой.

Давайте вычислим по этой формуле факториал числа 4. Сначала распишем рекуррентную формулу до базового значения — факториала числа 1:

Можно записать это и в сокращённом виде:

Теперь последовательно подставляем значение факториала, которое мы уже знаем, и вычисляем результат:

Получили ответ — 24. Ничего сложного, просто перемножаем числа.

Кстати, всю эту формулу можно обернуть в реально работающую функцию на языке Python:

Шпаргалка: таблица факториалов

Чтобы быстро находить, чему равен факториал, можно запомнить или сохранить в заметки вот такую табличку. Она рассчитана всего на 12 чисел, но для большинства учебных задач этого хватит.

1! 1
2! 2
3! 6
4! 24
5! 120
6! 720
7! 5040
8! 40 320
9! 362 880
10! 3 628 800
11! 39 916 800
12! 479 001 600

Примеры задач на факториалы с решениями

С теорией вроде разобрались — теперь попробуем решить несколько задач с факториалами, чтобы закрепить знания на практике.

Умножение факториалов

Задача: перемножить два факториала.

Решение:

Сперва нужно вычислить значения факториалов, а затем перемножить полученные значения:

Обратите внимание: во второй строке мы применили рекуррентную формулу, чтобы быстрее вычислить факториал числа 7.

Вычитание факториалов

Задача: вычесть из одного факториала другой.

Решение:

Используем тот же подход, что и в предыдущей задаче: сначала вычисляем факториалы, а затем получаем ответ на всё выражение.

Вроде бы ничего сложного, главное — не запутаться в умножении.

Перемножение факториалов

Задача: умножить один факториал на другой:

Решение:

Вычисляем факториалы, потом перемножаем их значения:

Во второй строке мы воспользовались таблицей выше и быстро нашли значение факториала от числа 8.

Сокращение факториалов

Задача: сократить дробь и вычислить её значение.

Решение:

Здесь мы воспользуемся рекуррентной формулой для вычисления факториала и разложим верхний факториал на множители:

В первой строке мы применили рекуррентную формулу два раза, а во второй — просто сократили одинаковые факториалы в числителе и в знаменателе.

Разложение факториалов

Задача: сократить дробь.

Решение:

Хотя здесь нет конкретных чисел, но принцип решения остаётся таким же: используем рекуррентную формулу и сокращаем одинаковые значения в числителе и знаменателе.

Главное — не запутаться и правильно применить рекуррентную формулу.

Что запомнить

  • Факториал — это произведение всех натуральных чисел от 1 до данного числа. Например, факториал числа 5 будет равен 1 × 2 × 3 × 4 × 5 = 120.
  • Его используют во многих областях науки — например, комбинаторике, теории вероятностей и математическом анализе.
  • Помимо стандартной формулы для вычисления факториала можно использовать формулы Стирлинга и рекуррентную формулу.
  • Формула Стирлинга нужна для того, чтобы посчитать факториал без большого числа операций умножения.
  • Рекуррентная формула позволяет вычислить факториал на основе предыдущего факториала.

Читайте также:

  • Интегралы: всё, что вы хотели знать, без интриг и сложных терминов
  • Заняться фронтенд-разработкой в 12 лет, выиграть IT‑чемпионат в 13: история Али Сулейманова
  • Чем различается фронтенд- и бэкенд-разработка

Натуральные числа — это числа, которыми мы считаем количество предметов. Например, 1, 2, 5, 20, 43. Натуральные числа не могут быть отрицательными, а также дробными — только положительными и целыми. Минимальное натуральное число — ноль, а максимальное — бесконечность.

Курс

Профессия Data Scientist

Освойте Data Science с нуля. Вы попробуете силы в аналитике данных, машинном обучении, дата-инженерии и подробно изучите направление, которое нравится вам больше. Отточите навыки на реальных проектах и станете востребованным специалистом.

Узнать про курс

Профессии с трудоустройством

  • Графический дизайнер
  • Python-программист
  • Инженер по тестированию
  • Бизнес-аналитик
  • Интернет-маркетолог 2023

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *