код для вычисления факториала
Алгоритмы быстрого вычисления факториала
Понятие факториала известно всем. Это функция, вычисляющая произведение последовательных натуральных чисел от 1 до N включительно: N! = 1 * 2 * 3 *… * N. Факториал — быстрорастущая функция, уже для небольших значений N значение N! имеет много значащих цифр.
Попробуем реализовать эту функцию на языке программирования. Очевидно, нам понадобиться язык, поддерживающий длинную арифметику. Я воспользуюсь C#, но с таким же успехом можно взять Java или Python.
Итак, простейшая реализация (назовем ее наивной) получается прямо из определения факториала:
На моей машине эта реализация работает примерно 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
Получается своеобразное дерево, где множители находятся в узлах, а результат получается в корне
Реализуем описанный алгоритм:
Для N=50 000 факториал вычисляется за 0,9 секунд, что почти вдвое быстрее, чем в наивной реализации.
Алгоритм вычисления факторизацией
Для наглядности посчитаем, сколько раз двойка содержится в 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, для этого можно использовать решето Эратосфена:
Эта реализация также тратит примерно 0,9 секунд на вычисление 50 000!
Как справедливо отметил pomme скорость вычисления факториала на 98% зависит от скорости умножения. Попробуем протестировать наши алгоритмы, реализовав их на C++ с использованием библиотеки GMP. Результаты тестирования приведены ниже, по ним получается что алгоритм умножения в C# имеет довольно странную асимптотику, поэтому оптимизация дает относительно небольшой выигрыш в C# и огромный в C++ с GMP. Однако этому вопросу вероятно стоит посвятить отдельную статью.
Все алгоритмы тестировались для N равном 1 000, 2 000, 5 000, 10 000, 20 000, 50 000 и 100 000 десятью итерациями. В таблице указано среднее значение времени работы в миллисекундах.
График с линейной шкалой
График с логарифмической шкалой
Идеи и алгоритмы из комментариев
Хабражители предложили немало интересных идей и алгоритмов в ответ на мою статью, здесь я оставлю ссылки на лучшие из них
Исходные коды реализованных алгоритмов приведены под спойлерами
Как вычислить факториал в Python?
Как вычислить факториал в Python?
Считать факториал в Python легко, если вам помогает питоновская программа, щелкающая математические операции, как орешки. Однако, прежде, чем Python порадует нас правильными рассчетами, придется нам порадовать Питона новой порцией отменного кода под названием «Факториал!». Но, сначала краткий математический ликбез:
Что такое факториал числа?
Факториалом числа N называется произведение всех чисел от единицы до N. О том, что речь идет о факториале, «говорит» восклицательный знак после числа N.
Например, факториал 5 считается так: 5! = 1*2*3*4*5
А факториал 12 равен: 12! = 1*2*3*4*5*6*7*8*9*10*11*12.
Кстати, факториал нуля равен единице, как и факториал самой единицы: 0! = 1 1! = 1
Это нужно запомнить, и обязательно закодить в своей программе!
Пишем код на Python для вычисления факториала
Внимание! При написании кода необходимо учесть, что нельзя вычислить факториал нецелого или отрицательного числа. Поэтому необходимо добавить соответствующую проверку!
Рассмотрим несколько вариантов написания кода:
1. Cамый простой вариант. Это будет цикл for, принимающий на вход число n и выводящий в ответ посчитанный факториал. Если число n является нецелым или отрицательным, выведем сообщение об ощибке. В качестве тренировки, после него рекомендую усложнить задачу и заключить цикл в функцию, как во втором варианте.
2. Вариант — это функция для вычисления факториала, которой в качестве аргумента будем передавать число n. Этот вариант является «причесанным» первым вариантом.
3. Вариант — это облагороженный 2-й вариант. Помимо того, что вычисление факториала будет производиться при вызове функции, так еще и программа любезно «попросит» пользователя ввести число, факториал которого нужно рассчитать.
Итак, приступим к реализации задуманных вариантов!
ВАРИАНТ №1: Пишем цикл for для вычисления факториала в Python!
Предлагаю сначала взглянуть на рабочий код. Позже мы рассмотрим каждый шаг подробно:
При значении num=5, результат работы кода выглядит следующим образом:
А при нецелом значении 3.2:
Разберем код варианта №1 подробно:
1. Объявляем переменную num и передаем ей число, факториал которого требуется найти:
2. Определяем переменную factorial, в которой будет храниться значение вычисленного факториала. В качестве начального значения устанавливаем «1»
3. Проверяем, верно ли задано значение переменной num. Если пользователь ввел нецелое число, тогда остаток от деления этого нецелого числа на единицу будет больше нуля.
Операция «%» в Python позволяет получить остаток от деления первого числа на второе. Например, 5%1 =0, а 5.5%1 = 0.5
Таким образом, чтобы проверить, является ли num, целым, нужно сравнить результат операции num%1 с нулем. Кроме этого, нужно убедиться, что число num не является отрицательным, для этого проверим выполнение неравенства num >= 0:
Добавим проверку перечисленных выше условий:
4. Вычислим значение факториала числа num. Для целого числа i, принимающего целые значения от 1(включительно) до n+1(не включительно), будем вычислять текущее значение факториала на i и присваивать факториалу новое полученное значение. То есть, при расчете 4! будут происходить действия:
5. Вывод результата на экран осуществим в виде строки:
Такая конструкция (с буквой f перед кавычками) позволяет вывести значение переменной, заключенной в фигурные скобки. В итоге, код приобретет вид:
ВАРИАНТ №2: Создаем функцию для вычисления факториала!
1. Для начала объявим функцию find_factorial(num), которая в качестве аргумента будет принимать число, факториал которого требуется вычислить:
2. Определяем переменную для хранения текущего значения факториала, присваиваем ей значение «1»:
3. Затем, весь написанный в «Варианте №1» код, начиная с проверки на корректность переменной num, помещаем в функцию find_factorial(num). При этом нужно заменить «print» на «return», так как функция ничего не будет выводить на экран, а будет возвращать полученное значение факториала или сообщение об ошибке:
Если какой-то момент в коде для Вас не понятен, перечитайте внимательно приведенный выше детальный разбор кода в «Варианте 1»
4. Осталось только вызвать нашу новую функцию и проверить, корректно ли она работает. Для этого определим число, факториал которого будем считать. Затем вызовем функцию find_factorial() для вычисления факториала числа num. Полученный от функции ответ сохраним в переменной factorial и выведем эту переменную на экран:
Наша функция отлично работает и может стать полезным ингредиентом в самописной библиотеке для математических вычислений! Однако, мы можем украсить наш код небольшой изюминкой, чем и займемся при рассмотрении «Варианта №3».
ВАРИАНТ №3: Облагородим код, вычисляющий факториал в Python, строкой пользовательского ввода.
Давайте добавим скрипту интерактивности — вежливо попросим пользователя ввести число, факториал которого нужно вычислить. Затем, после ввода числа и нажатия пользователем клавиши «Enter», обратимся к функции find_factorial() и выведем результат на экран. Для этого требуется лишь заменить строку, в которой мы задавали значение переменной num, следующей строкой:
Функция input() в Python3 позволяет получить введенную пользователем информацию.
Функция eval() позвляет динамически обновить данные.
В итоге, обновленный работающий код будет выглядеть так:
Мы рассмотрели 3 варианта, от самого простого, до самого «облагороженного», которые можно использовать для решения задачи по вычислению факториала в Python. Несмотря на то, что эта задача является довольно простой, она отлично подходит для тренировки навыков программирования в Python!
Пятничный JS: единственно верный способ вычисления факториала
Введение
Вычисление факториала — одна из традиционных программистских задач для собеседований. Если вдруг кто забыл, факториал натурального числа N обозначается как N! и равняется произведению всех натуральных чисел от единицы до N включительно. Например, . Казалось бы, что тут сложного? Однако есть свои нюансы.
Например, сравним два самых распространённых способа вычисления факториала.
Многие скажут, что первый способ лучше, но это не так. Во-первых, циклы уже не в тренде, сейчас модно функциональное программирование. Во-вторых, чем больше людей используют второй способ, тем быстрее в основных джаваскриптовых движках появится оптимизация хвостовой рекурсии.
В любом случае, оба эти способа слишком примитивны, чтобы по ним судить о знаниях кандидата. А вот опытный разработчик на React.js уже может написать что-то в этом роде:
Согласитесь, выглядит гораздо солиднее. Впрочем, невооружённым глазом видно, что это всего лишь вариант рекурсивного вычисления. Сходство станет ещё сильнее, если переписать Factorial как функциональный компонент. И, разумеется, я не стал бы писать этот хабрапост, если бы не был готов предложить нечто принципиально новое.
Начнём издалека
Какую из возможностей Javascript недолюбливают и недооценивают сильнее всего? Недолюбливают настолько, что про неё даже придумали специальную поговорку? Конечно же, это eval. Можно сказать, что eval — это тёмная сторона Силы. А как мы помним из фильмов Джорджа Лукаса, нет ничего более крутого и впечатляющего, чем тёмная сторона Силы, поэтому давайте попробуем ей овладеть.
Можно было бы запихнуть в строку какой-нибудь из методов, приведённых в начале поста, а затем передать эту строку в eval, но в этом не было бы новизны. Поставим задачу таким образом, чтобы сделать этот хак невозможным. Пусть у нас есть такой вот каркас:
— и мы хотим, внеся изменения лишь в литерал строки f, сделать так, чтобы функция factorial взаправду вычисляла факториал. Вот задача, достойная истинного ситха.
Что-то это напоминает
Нам нужен код, который возвращает код, который возвращает код… Если забыть про конечную задачу — вычисление факториала, то есть одна хорошо известная штука, которая нам подойдёт. Эта штука называется квайн — программа, которая выводит свой собственный текст.
Про квайны на Хабре написано уже немало, потому я напомню лишь основные принципы квайностроительства. Чтобы сделать простейший квайн, нам нужно:
В строке o.s содержится весь остальной код, а также специальные подстановочные последовательности, начинающиеся с подчёркивания. Страшное выражение внутри console.log заменяет каждую подстановочную последовательность на соответствующее свойство объекта o, что обеспечивает выполнение пунктов 2 и 3 хитрого плана по созданию квайна.
Здесь меня могут поправить: товарищ, это не простейший квайн, а монстр какой-то. Простейший квайн на js выглядит так:
Это правда, но не совсем. Такой квайн считается «читерским», поскольку он из тела функции получает доступ к её же тексту. Это почти то же самое, что прочитать с жёсткого диска файл с исходным кодом программы. Моветон, одним словом.
Скрещиваем ежа с ужом
Как же сделать так, чтобы наш квази-квайн модифицировал сам себя, а в результате превратился в одно-единственное число? Давайте забудем пока про вычисление факториала и постараемся просто написать строку, которая «схлопывается» через определённое количество eval’ов. Для этого нам понадобится:
Обратите внимание на отсутствие return внутри строки: в нём нет необходимости, eval возвращает значение последнего выражения. Запустив этот код в консоли, можно c благоговением наблюдать, как с каждой итерацией цикла значение n уменьшается на 1. Если кто-то скажет, что для такого эффекта достаточно:
— то у него нет чувства прекрасного.
После этого подготовительного этапа уже совсем нетрудно написать итоговую версию вычисления факториала. Просто добавляется ещё одна переменная и чуть усложняется строчка с изменением.
Теперь вы можете смело идти на собеседование.
Заключение
С живым кодом можно поиграться здесь. Как и в прошлой статье из рубрики «Пятничный JS» напоминаю: если вы сделаете что-нибудь подобное на продакшене, то попадёте в ад. С другой стороны, если вы сделаете это на собеседовании, то вам не дадут возможности сделать это на продакшене, и вы не попадёте в ад. Так что делайте это на собеседовании. Спасибо за внимание.
Магия шаблонов или вычисление факториала на стадии компиляции
Доброго времени суток, Хабралюди!
Гуру C++, а также люди смыслящие в шаблонном метапрограммировании могут смело пропускать этот топик, ничего нового для себя они здесь не найдут. Однако, если после прочтения заголовка, у вас в голове еще не возникло решение данной задачи (и даже если оно возникло, но не при помощи шаблонов), то милости просим под кат.
Собственно, решение задачи:
Давайте разберемся, что к чему. Во-первых, некоторые могут спросить — а почему значение вычисляется на стадии компиляции? Ответ — это основа шаблонов в C++. Специализированный код генерируется на стадии компиляции, в зависимости от того каким типом реально был параметризован шаблон. Суть в том, что если вы используете, например, шаблон функции, которая возвращает минимум двух значений:
То если использовать в программе, например:
То сгенерируется только специализация для типа int. А если написать, что-то вроде:
То сгенерируется специализация для double.
Теперь, возвращаясь к нашему факториалу, можно понять, что для генерации шаблона Factorial должен сгенерироваться шаблон Factorial и так далее до нуля, где в Factorial ::f записывается просто единица (за счет явной специализации template<>). Этот последний шаг останавливает «рекурсивную» генерацию шаблонов, после чего вычисляется само значение факториала. Почему на стадии компиляции? Потому что константа static const int f является константой времени компиляции. Если кто-то не верит в это, можете задать какое-нибудь значение шаблона в качестве длины массива, и наблюдать спокойную компиляцию программы.
В книге Брюса Эккеля Философия С++. Практическое программирование. Приводится следующее решение этой задачи (которое по сути ничем не отличается от вышеописанного):
Вообще, такое вычисление факториала является частным случаем шаблонного метапрограммирования. Например, возведение в степень q, целого числа p, можно было бы написать циклом:
Но также можно и при помощи шаблонного метапрограммирования:
Более подробно об этом можно прочесть, например, у Эккеля, в книге Философия С++. Практическое программирование, или у Александреску в книге Современное проектирование на C++.
Написать функцию вычисления факториала
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Написать функцию вычисления факториала
И еще вот эти две пожалуйста. 2. Написать функцию вычисления факториала (факториалом целого.
Написать рекурсивную функцию вычисления факториала
1. Написать рекурсивную функцию вычисления факториала. помогите понять рекурсию
Написать функцию возвращающую ответ вычисления факториала
Доброго времени суток. Нужно решить три задачки. Я с С++ сталкиваюсь только сейчас. 2)Написать.
Написать программу, которая выводит значения факториалов чисел от 0 до N. Для вычисления факториала числа написать функцию пользователя
Написать программу, которая выводит значения факториалов чисел от 0 до N. Для вычисления факториала.
Отличное качество! это же главный двигатель прогресса!
Мне вот тоже лень чего-делать самому. Сижу себе на пенечке, и комментирую.
Добавлено через 6 минут
Добавлено через 3 минуты
Добавлено через 7 минут
Тогда так
Согласен. Но в ТЗ сказано написать функцию. Скучная задача: факториалы, влезающие в стандартные типы, быстро закончатся, сработает любое решение в лоб. Не понятно, чему тут нужно научиться, решая её.
Помощь в написании контрольных, курсовых и дипломных работ здесь.
Напишите программу вычисления суммы: 1! + 2! + 3! + … + n!, используя функцию вычисления факториала числа k.
Напишите программу вычисления суммы: 1! + 2! + 3! + … + n!, используя функцию вычисления факториала.
Реальзовать Функцию вычисления факториала числа
Функция вычисления факториала числа..
Написать программу вычисления факториала
1. Для заданного натурального числа n написать программу вычисления его факториала: n! = 1*2* … *n.
Написать программу для вычисления факториала
Помогите! заранее спасибо!
Написать программу для вычисления факториала числа
1) написать программу для вычисления факториала числа n!=1*2*3. *n. Число n вводится с клавиатуры
Написать программу для вычисления двойного факториала числа
2) написать программу для вычисления двойного факториала числа n!!=n*(n-2)*(n-4)*(n-6). Число n.