Создайте самую короткую программу или функцию, которая находит факториал неотрицательного целого числа.
Факториал, представленный !
как, определяется как таковой
В простом английском языке факториал 0 равен 1, а факториал n, где n больше 0, в n раз больше факториала на единицу, чем n.
Ваш код должен выполнять ввод и вывод, используя стандартные методы.
Требования:
- Не использует никаких встроенных библиотек, которые могут вычислить факториал (включая любую форму
eval
) - Можно рассчитать факториалы для чисел до 125
- Можно рассчитать факториал для числа 0 (равно 1)
- Завершается менее чем за минуту для номеров до 125
Получается самое короткое представление, в случае ничьей выигрывает ответ, набравший наибольшее количество голосов.
code-golf
arithmetic
factorial
Кевин Браун
источник
источник
Ответы:
Golfscript - 12 символов
Начало работы с Golfscript - Факториал шаг за шагом
Вот кое-что для людей, которые пытаются выучить гольф. Обязательным условием является базовое понимание гольф-скрипта и умение читать документацию по гольф-скрипту.
Поэтому мы хотим опробовать наш новый инструмент golfscript . Всегда хорошо начинать с чего-то простого, поэтому мы начинаем с факториала. Вот начальная попытка, основанная на простом императивном псевдокоде:
Пробелы в гольскрипте очень редко используются. Самый простой способ избавиться от пробелов - использовать разные имена переменных. Каждый токен может использоваться как переменная (см. Страницу синтаксиса ). Полезные маркеры для использования в качестве переменных специальные символы , такие как
|
,&
,?
- вообще ничего не используется в других местах в коде. Они всегда анализируются как токены одного символа. Напротив, переменные типа liken
потребуют пробела для добавления числа в стек после. Числа по существу являются преинициализированными переменными.Как всегда, будут утверждения, которые мы можем изменить, не влияя на конечный результат. В golfscript, все оценивается как истина , за исключением
0
,[]
,""
и{}
(см это ). Здесь мы можем изменить условие выхода из цикла на простое{n}
(мы добавляем цикл в дополнительное время и завершаем работу, когда n = 0).Как и при игре в гольф на любом языке, это помогает узнать о доступных функциях. К счастью, список очень короток для гольфа. Мы можем изменить ,
1-
чтобы(
спасти другой персонаж. В настоящее время код выглядит следующим образом: (мы могли бы использовать1
вместо этого,|
если бы мы хотели, что бы сбросить инициализацию.)Важно правильно использовать стек, чтобы получить кратчайшие решения (практика, практика). Как правило, если значения используются только в небольшом сегменте кода, может не потребоваться сохранять их в переменных. Удаляя переменную product product и просто используя стек, мы можем сохранить довольно много символов.
Вот о чем еще подумать. Мы удаляем переменную
n
из стека в конце тела цикла, но затем добавляем ее сразу после. Фактически, перед началом цикла мы также удаляем его из стека. Вместо этого мы должны оставить его в стеке, и мы можем оставить условие цикла пустым.Может быть, мы можем даже полностью исключить переменную. Для этого нам нужно будет постоянно хранить переменную в стеке. Это означает, что нам нужно две копии переменной в стеке в конце проверки условия, чтобы мы не потеряли ее после проверки. Это означает, что у нас будет избыточность
0
в стеке после окончания цикла, но это легко исправить.Это приводит нас к нашему оптимальному
while
циклическому решению!Теперь мы все еще хотим сделать это короче. Очевидной целью должно быть слово
while
. Глядя на документацию, есть две жизнеспособные альтернативы - развернуть и сделать . Если у вас есть выбор различных маршрутов, попробуйте взвесить преимущества обоих. Развернуть это «довольно много времени цикла», так что в качестве оценки мы сократим 5 символовwhile
на 4 в/
. Что касаетсяdo
, мы разрезаемwhile
на 3 символа и получаем объединение двух блоков, что может сохранить еще один или два символа.На самом деле есть большой недостаток в использовании
do
цикла. Поскольку проверка условия выполняется после однократного выполнения тела, значение0
будет неправильным, поэтому нам может понадобиться оператор if. Я вам сейчас скажу, что разворачивается короче (do
в конце представлены некоторые решения с ). Попробуйте и попробуйте, код, который у нас уже есть, требует минимальных изменений.Большой! Наше решение теперь очень короткое, и мы здесь, верно? Нет. Это 17 символов, а у J 12 символов. Никогда не признай поражение!
Теперь вы думаете с ... рекурсией
Использование рекурсии означает, что мы должны использовать ветвящуюся структуру. К сожалению, но так как факториал можно выразить так кратко, рекурсивно, это кажется жизнеспособной альтернативой итерации.
Ну, это было легко - если бы мы попробовали рекурсию раньше, мы могли бы даже не взглянуть на использование
while
цикла! Тем не менее, мы только на 16 символов.Массивы
Массивы обычно создаются двумя способами - с помощью
[
и]
символов, или с,
функцией. Если выполняется с целым числом в верхней части стека,,
возвращает массив этой длины с arr [i] = i.Для перебора массивов у нас есть три варианта:
{block}/
: толкать, блокировать, толкать, блокировать, ...{block}%
: [push, block, push, block, ...] (здесь есть некоторые нюансы, например, промежуточные значения удаляются из стека перед каждым push){block}*
: толкать, толкать, блокировать, толкать, блокировать, ...В документации по гольфу есть пример использования
{+}*
для суммирования содержимого массива. Это говорит о том, что мы можем использовать,{*}*
чтобы получить произведение массива.К сожалению, не все так просто. Все элементы отключены одним (
[0 1 2]
вместо[1 2 3]
). Мы можем использовать,{)}%
чтобы исправить эту проблему.Ну, не совсем. Это не обрабатывает ноль правильно. Мы можем вычислить (n + 1)! / (N + 1), чтобы исправить это, хотя это стоит слишком дорого.
Мы также можем попытаться обработать n = 0 в том же сегменте, что и n = 1. Это на самом деле очень коротко, попытаться выработать как можно меньше.
Если мы хотим, чтобы приращение и умножение были в одном и том же блоке, мы должны выполнять итерации по каждому элементу в массиве. Поскольку мы не создаем массив, это означает, что мы должны его использовать
{)*}/
, что приводит нас к кратчайшей реализации факториала в golfscript! В 12 символов, это связано с J!Бонусные решения
Начиная с простого
if
решения дляdo
цикла:Мы можем выжать пару лишних из этого. Немного сложно, так что вам придется убедить себя, что эти работы. Убедитесь, что вы понимаете все это.
Лучшей альтернативой является вычисление (n + 1)! / (N + 1), что устраняет необходимость в
if
структуре.Но самое короткое
do
решение здесь занимает несколько символов, чтобы отобразить 0 к 1, и все остальное для себя - так что нам не нужно никаких ветвлений. Этот вид оптимизации чрезвычайно легко пропустить.Для тех, кто заинтересован, здесь представлено несколько альтернативных рекурсивных решений такой же длины, как указано выше:
* примечание: на самом деле я не тестировал многие фрагменты кода в этом посте, поэтому не стесняйтесь сообщать, если есть ошибки.
источник
Хаскелл, 17
источник
[1..0] ==> []
иproduct [] ==> 1
f 0=1;f n=n*f$n-1
содержит 17 символов.product
и, скажем,(*)
или(-)
«можно рассчитать факториал», и все они определены с помощью Prelude. Почему один будет классным, а не другой?Python - 27
Просто:
источник
0**x
.math.factorial
? Это не встроенный, не так ли?0**x
?APL (4)
Работает как анонимная функция:
Если вы хотите дать ему имя, 6 символов:
источник
⍳
делает вектор индекса, т.е.⍳5
есть1 2 3 4 5
.×
(очевидно) умножить,/
уменьшить, и∘
является композицией функций. Итак,×/∘⍳
это функция, которая принимает аргументx
и дает произведение чисел[1..x]
.J (12)
Стандартное определение в J:
Менее 1 секунды на 125!
Например:
источник
([:*/1+i.)
для 10 баллов или даже 8, так как скобки нужны только для вызова функции, а не для определения.f 125x
что делаетx
? Это особый вид номера?Golfscript - 13 символов (SYM)
определяет функцию
!
альтернативная версия на 13 символов
вся версия программы 10 символов
Тестовые случаи занимают менее 1/10 секунды:
вход:
выход
вход
выход
источник
Perl 6: 13 символов
[*]
такой же, как у Haskellproduct
, и1..$_
считается от 1 до$_
аргумента.источник
[*]
(сообщение об ошибке «Два члена подряд»).Матлаб, 15
Тестовые случаи
источник
Python, 28 байт
(на основе решения Александру)
источник
MATL , 2 байта
Разъяснение:
Попробуйте онлайн!
источник
Рубин - 21 символ
Контрольная работа
источник
Ява, 85 символов
источник
import java.math.*;
(так, +19 байт).PostScript, 26 символов
Пример:
Сама функция занимает всего 21 символ; остальное - привязать его к переменной. Чтобы сохранить байт, можно также привязать его к цифре, например так:
источник
1.#INF
. (Я использовал акцию GNU Ghostscript 9.0.7 , скомпилированные для 64 - разрядной Windows.)JavaScript, 25
CoffeeScript, 19
Возвращает
true
в случае n = 0, но JavaScript все равно приведет к 1.источник
return
оператор в функции JavaScript?return
! Но почему нет?function f(n)n?n*f(--n):1
f=n=>!n||n*f(n-1)
Возьми это, CoffeeScript!Рубин -
3029 символовКонтрольная работа
источник
end
сразу после:*
без новой строки или точки с запятой.(1..10).inject :*
# => 3628800f(0)
?f=->n{(1..n).inject 1,:*}
. Назовите егоf[n]
.F #: 26 символов
Там нет встроенной функции продукта в F #, но вы можете сделать один со сгибом
источник
C #, 20 или 39 символов в зависимости от вашей точки зрения
Как традиционный метод экземпляра (39 символов; проверено здесь ):
Как лямбда-выражение (20 символов, но см. Заявление об отказе от ответственности; проверено здесь ):
Мы должны использовать,
double
потому что 125! == 1.88 * 10 209 , что намного выше, чемulong.MaxValue
.Отказ от ответственности за количество символов лямбда-версии:
Если вы выполняете рекурсию в лямбде C #, вам, очевидно, придется хранить лямбда в именованной переменной, чтобы она могла вызывать себя. Но, в отличие от (например, JavaScript), лямбда с самообращением должна быть объявлена и инициализирована в предыдущей строке. Вы не можете вызывать функцию в том же операторе, в котором вы объявляете и / или инициализируете переменную.
Другими словами, это не работает :
Но это делает :
Для этого ограничения нет веских причин, поскольку
f
его нельзя отменять во время его работы. НеобходимостьFunc<int,double> f=null;
строки - это причуда C #. Делает ли это справедливым игнорировать это при подсчете символов - решать читателю.CoffeeScript,
2119 символов для настоящихПротестировано здесь: http://jsfiddle.net/0xjdm971/
источник
Брахилог ,
76 байтДелая диапазон и умножая его
Танки -1 байт для ов, имеющих идею использовать функцию max ()
объяснение
Попробуйте онлайн!
Брахилог ,
109 байтрекурсия
объяснение
Попробуйте онлайн!
источник
;
вместо,
позволяет только обычный числовой ввод. -1 байт в любом случаеС (39 символов)
источник
double f(n){return!n?1:n*f(n-1);}
- 33 символа .f(125)
будет переполненD: 45 символов
Более разборчиво:
Кулер (хотя и более длинная версия) - шаблонизированный, который делает все это во время компиляции ( 64 символа ):
Более разборчиво:
Тем не менее, одноименные шаблоны довольно многословны, так что вы не можете использовать их в код-гольфе очень хорошо. D уже достаточно многословен с точки зрения количества символов, чтобы быть достаточно плохим для гольф-кода (хотя на самом деле он действительно хорош при уменьшении общего размера программы для больших программ). Хотя это мой любимый язык, поэтому я полагаю, что с таким же успехом я мог бы попытаться увидеть, насколько хорошо я смогу это сделать в кодовом гольфе, даже если подобный GolfScript не лишен этого.
источник
PowerShell - 36
Наивный:
Контрольная работа:
источник
Скала, 39 знаков
Большинство символов гарантируют, что
BigInt
используются s, так что требование к значениям до 125 выполняется.источник
(x:Int)=>(BigInt(1)to x).product
def f(x:Int)=(BigInt(1)to x).product
def f(x:BigInt)=(x.to(1,-1)).product
def f(x:BigInt)=(-x to-1).product.abs
Javascript, ES6 17
ES6:
источник
PowerShell, 42 байта
(сохранил 2 символа, используя фильтр вместо функции )
Выход:
источник
filter f($x){if($x){$x*(f($x-1))}else{1}}
. И он может быть уменьшен до 36 символов, если он вызывается через конвейер, так как это фильтр (например125|f
):filter f{if($_){$_*($_-1|f)}else{1}}
Ракетка (схема)
403529 байтВычисляет 0! быть 1, и вычисляет 125! в 0 секунд по таймеру. Регулярный рекурсивный подход
Новая версия, чтобы превзойти общий lisp: умножает все элементы списка (так же, как это решение на Haskell)
Более новая версия, чтобы превзойти другое решение схемы и математическое решение другой ракетки, используя foldl вместо apply и используя range вместо buildlist
источник
Морнингтон Полумесяц ,
18271698 символовЯ чувствовал, что изучаю новый язык сегодня, и это то, на чем я остановился ... (Почему я делаю это для себя?) Эта запись не будет выигрывать какие-либо призы, но она побеждает все 0 других ответов до сих пор, используя тот же язык!
Попробуйте онлайн!
Любой, кто путешествовал по Лондону, сразу же это поймет, поэтому я уверен, что мне не нужно давать полное объяснение.
Большая часть работы на старте заключается в обработке случая 0. После инициализации продукта в 1, я могу использовать это для вычисления max (input, 1), чтобы получить новый ввод, используя тот факт, что 0! = 1! Тогда основной цикл может начаться.
(РЕДАКТИРОВАТЬ: целая куча поездок была спасена путем удаления 1 из «Терминалов Хитроу 1, 2, 3» вместо генерации ее путем деления 7 (сестер) на себя. Я также использую более дешевый метод для генерации -1 в следующий шаг.)
В Mornington Crescent декрементирование стоит дорого (хотя и дешевле, чем сама Tube). Чтобы сделать вещи более эффективными, я генерирую -1, беря NOT из анализируемого 0 и сохраняю его в Hammersmith для большей части цикла.
Я вложил в это значительную работу, но поскольку это моя первая попытка игры в гольф в Морнингтон-Кресент (фактически моя первая попытка на любом языке), я ожидаю, что пропустил несколько оптимизаций здесь и там. Если вы сами интересуетесь программированием на этом языке (а почему бы и нет?), Esoteric IDE - с его режимом отладки и окном просмотра - просто необходимо!
источник
Befunge - 2x20 = 40 символов
Это функция в том смысле, что это автономный блок кода, не использующий обтекание. Вы должны поместить аргумент в верхнюю часть стека, затем войти в верхний левый угол, идущий вправо, функция выйдет из нижнего правого угла, идущего вправо, с результатом на вершине стека.
Например, чтобы вычислить факториал 125
Тестирование 0
источник
&:!#@_>:# 1# -# :# _$>\# :#* _$.@
(где & должно быть заменено вводом). Это 32 символа / байтаJ - 6 символов
Это считается? Я знаю, что это очень похоже на предыдущий пример J, но оно немного короче :)
Я новичок с J, но это очень весело!
источник
В С (23 символа)
Это нарушает «особенность» GCC, которая делает счет последнего присваивания в качестве возврата, если возврат не указан.
В правильном C, 28 символов
источник
0 == ({printf("Hello, world!"); 0;});
Кона (
116)K работает справа налево (по большей части), поэтому мы перечисляем
x
(составляем список / массив чисел от0
доx-1
), добавляем1
к нему (список варьируется0
доx
), затем умножаем все числа вместе. Если бы это не было требованием для вычисления125!
, я мог бы сохранить еще 1 байт, исключив.
рядом с1
. В любом случае 125! вычисляется в миллисекундах:источник
*/1.+!
: 6 байтов.