54
\$\begingroup\$

Task

Given a non-negative integer \$n\$, evaluate the factorial \$n!\$.

The factorial is defined as follows:

$$ n!=\begin{cases}1 & n=0\\n\times(n-1)!&n>0\end{cases} $$

Rules

  • All default I/O methods are allowed.
  • Standard loopholes are forbidden.
  • Built-ins are allowed.
  • There is no time or memory limit.
  • Giving imprecise or incorrect results for large inputs due to the limit of the native number format is fine, as long as the underlying algorithm is correct. Specifically, it is not allowed to abuse the native number type to trivialize the challenge, which is one of the standard loopholes.
  • This is . Shortest code in bytes wins, but feel free to participate in various esolangs (especially the ones hindered by the restrictions of the former challenge).

Test cases

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600

Note: We already have the old factorial challenge, but it has some restrictions on the domain, performance, and banning built-ins. As the consensus here was to create a separate challenge without those restrictions so that more esolangs can participate, here it goes.

Also, we discussed whether we should close the old one as a duplicate of this, and we decided to leave it open.

\$\endgroup\$

146 Answers 146

1
2 3 4 5
33
\$\begingroup\$

Shakespeare Programming Language, 106 bytes

,!Ajax,!Puck,!Act I:!Scene I:![Enter Ajax and Puck]Ajax:Listen tothy!You is the factorial ofyou!Open heart

Try it online!

Uses the built-in the factorial of, which isn't described at all in the official docs.

Commented

,!Ajax,!Puck,!Act I:!Scene I:![Enter Ajax and Puck] # header
Ajax:Listen tothy!                                  # read (numeric) input
You is the factorial ofyou!                         # take factorial
Open heart                                          # numeric output
\$\endgroup\$
0
20
\$\begingroup\$

MATL, 2 bytes

:p

Try it online!

The : generates a range from 1 to input inclusive and the p reduces it on product

\$\endgroup\$
4
  • 17
    \$\begingroup\$ I like the emoticon :p \$\endgroup\$
    – user96495
    Aug 25, 2020 at 2:15
  • 1
    \$\begingroup\$ PERFECT. love that emoticon. \$\endgroup\$
    – matt
    Sep 9, 2020 at 17:55
  • \$\begingroup\$ PERFECT EMOTICON. \$\endgroup\$
    – Joao-3
    Mar 18, 2022 at 18:10
  • \$\begingroup\$ There can't be shorter. \$\endgroup\$
    – gildux
    Jan 16 at 8:14
19
\$\begingroup\$

C (gcc), 21 bytes

Uses the assignment trick, works consistently in GCC without optimizations.

O(o){o=o?o*O(~-o):1;}

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ What's the assignment trick? \$\endgroup\$
    – Quelklef
    Aug 25, 2020 at 21:51
  • 2
    \$\begingroup\$ @Quelklef see here stackoverflow.com/questions/4644860/… \$\endgroup\$
    – AZTECCO
    Aug 25, 2020 at 23:13
  • \$\begingroup\$ Undefined behavior? \$\endgroup\$
    – Dúthomhas
    Aug 26, 2020 at 1:45
  • 7
    \$\begingroup\$ Why ~-o and not o-1? \$\endgroup\$
    – retnikt
    Aug 27, 2020 at 11:33
  • 4
    \$\begingroup\$ Guess what? I read this program in ghost voice. \$\endgroup\$
    – user96495
    Sep 5, 2020 at 13:32
18
\$\begingroup\$

x86-16 / x87 machine code, 13 bytes

Binary:

00000000: d9e8 e308 518b f4de 0c59 e2f8 c3         ....Q....Y...

Listing:

D9 E8       FLD1                ; start with 1 
E3 08       JCXZ DONE           ; if N = 0, return 1 
        FACT_LOOP: 
51          PUSH CX             ; push current N onto stack
8B F4       MOV  SI, SP         ; SI to top of stack for N 
DE 0C       FIMUL WORD PTR[SI]  ; ST = ST * N 
59          POP  CX             ; remove N from stack 
E2 F8       LOOP FACT_LOOP      ; decrement N, loop until N = 0
        DONE: 
C3          RET                 ; return to caller

Callable function. Input \$n\$ in CX, output \${n!}\$ in ST(0). Works for values of \$n\$ up to 21 (before loss of precision).

Or recursive...

x86-16 / x87 machine code, 15 bytes

D9 E8       FLD1                ; start with 1
        FACT_CALL:
E8 0A       JCXZ DONE           ; if N = 0, end recursion
51          PUSH CX             ; push current N onto stack
49          DEC  CX             ; decrement N
E8 F9FF     CALL FACT_CALL      ; recurse N-1
8B F4       MOV  SI, SP         ; SI to top of stack for N
DE 0C       FIMUL WORD PTR[SI]  ; ST = ST * N
59          POP  CX             ; remove N from stack
        DONE:
C3          RET                 ; return from recursive call

Or x64 just for grins...

x86_64 machine code, 12 11 bytes

  31:   6a 01            push   0x1             # start with 1
  33:   58               pop    rax
  35:   e3 05            jrcxz  3c <done>       # if 0, return 1
0037 <f_loop>:
  37:   48 f7 e1         mul    rcx             # rax = rax * N
  3a:   e2 fb            loop   37 <f_loop>     # loop until N = 0
003c <done>:
  3c:   c3               ret                    # return to caller

Try it online!

Input \$n\$ in rcx, output \${n!}\$ in rax for values of \$n\$ up to 20.

  • -1 bytes thx to @PeterCordes on x86_64!
\$\endgroup\$
8
  • 1
    \$\begingroup\$ Foiled once again by the limitations of x86-16's memory addressing modes! Would have been nice to elide that mov si, sp by just doing a fimul WORD PTR [sp] to load directly from the stack pointer. Oh well. \$\endgroup\$ Aug 26, 2020 at 0:37
  • 1
    \$\begingroup\$ @CodyGray: You can do that in 32-bit code with the same machine code for everything else, except the ModRM byte for fimul dword ptr [esp]. Net savings of 1 byte because encoding that [esp] addressing mode requires a SIB; the unfortunate price x86 pays for more flexible addressing modes. They could have chosen ECX or something to be the special-case register that needs a longer encoding, instead of pessimizing -fomit-frame-pointer code :/. Also, obviously pure integer with mul cx or ecx would be more compact but less interesting. \$\endgroup\$ Aug 27, 2020 at 5:53
  • \$\begingroup\$ If not for longer [esp] addressing modes, there might have been something to gain by taking a stack arg so you don't have to manually push/pop. Or perhaps taking a value by non-const reference, e.g. pointed-to by di. Start with a jmp to the loop condition at the bottom instead of jecxz, and you can maybe use dec word ptr [di] / jg : 2+2 = 4 bytes instead of 6 total for mov si,sp / push/pop/loop. Or saves 1 byte in 32-bit mode (the [edi] instead of [esp] addressing mode). But hard to justify the destroying the by-reference arg. \$\endgroup\$ Aug 27, 2020 at 6:00
  • \$\begingroup\$ Would be 9 bytes (fld1, fimul [di], dec [di], jnz, ret) if we didn't have to worry about that "pesky" 0 case! \$\endgroup\$
    – 640KB
    Aug 27, 2020 at 14:17
  • 1
    \$\begingroup\$ Your x86-64 version can start with push 1 / pop rax. It's always possible to create a small value in a register in 3 bytes, sometimes with lea reg, [reg+disp8], or worst case push imm8. tips (xor/inc is not break-even with those in 64-bit mode because the 1-byte inc/dec encodings were repurposed as REX prefixes. That trick is only good in 16 / 32-bit mode. Also, I wish AMD64 had used one of the other removed opcode bytes for a mov r/m32, sign_extended_imm8 opcode to make stores and register-init with constants efficient in 3 bytes.) \$\endgroup\$ Aug 27, 2020 at 20:50
11
\$\begingroup\$

Google Sheets / Excel / Numbers, 8 bytes

=FACT(A1

All three spreadsheet programs close parentheses automatically.

\$\endgroup\$
2
  • \$\begingroup\$ my IDE also closes parentheses, but that doesn't make it a correct program in the language before closing right? \$\endgroup\$ Aug 28, 2020 at 12:54
  • \$\begingroup\$ @JensRenders There was a discussion in the meta about this. The currently discussion seems inconclusive, but leans on the side of counting them. When the first answer was posted (for not counting parens), I had less than 1k rep, so I couldn't see the breakdown, but I ran with that for a long time. I think a lot of answers here are in the same boat, unfortunately. Given the somewhat ironic and non-competitive nature of the language, maybe it's best to leave it up to the poster. \$\endgroup\$ Feb 15, 2021 at 21:09
11
\$\begingroup\$

brainfuck, 56 bytes

+>,[[>+>+<<-]>[-<<[->+<<+>]<[->+<]>>>]<<[-]>[->+<]>>-]<.

Try it online!

Takes input and outputs as byte values. Since this interpreter has 8 bit size cells, it can't really do anything larger than 5!. You can use this interpreter to try larger values.

\$\endgroup\$
10
\$\begingroup\$

Retina, 29 bytes

.+
*
.
$.<'$*
~`.+
.+¶$$.($&_

Try it online! Explanation:

.+
*

Convert n to unary.

.
$.<'$*

Count down from n in decimal, with trailing *s.

~`.+
.+¶$$.($&_

Wrap the result in a Retina replacement stage and evaluate it.

Example: For n=10, the resulting stage is as follows:

.+
$.(10*9*8*7*6*5*4*3*2*1*_

This calculates the length of the string obtained by repeating the _ by each of the numbers from 1 to 10.

Explanation for n=0:

.+
*

Delete the input.

.
$.<'$*

Do nothing.

~`.+
.+¶$$.($&_

Do nothing, and evaluate the resulting empty stage on the empty string.

The empty stage returns 1 more than the character count. As the string is empty, this is just 1. Conveniently, this is the result we wanted all along.

It is of course possible to calculate the factorial properly even for n=0, but my best attempt took 30 bytes.

\$\endgroup\$
10
\$\begingroup\$

Wolfram Language (Mathematica), 11 bytes

Gamma[#+1]&

Try it online!

Wolfram Language (Mathematica), 15 bytes

1~Pochhammer~#&

Try it online!

Wolfram Language (Mathematica), 19 bytes

If[#>0,#0[#-1]#,1]&

Try it online!

Wolfram Language (Mathematica), 24 bytes

The determinant of the n*n matrix of reciprocals of beta functions is n!

Det[1/Beta~Array~{#,#}]&

Try it online!

Wolfram Language (Mathematica), 26 bytes

GroupOrder@*SymmetricGroup

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Hah very original answers :-D. But why not the obvious #!&? \$\endgroup\$ Aug 27, 2020 at 13:03
  • \$\begingroup\$ @freddieknets The obvious one had been already posted by another user \$\endgroup\$
    – ZaMoC
    Aug 27, 2020 at 14:04
10
+500
\$\begingroup\$

///, 80 bytes

/!1/1!//!/S'SS'.'//1/S.B'S.B|B'SS.B|S|.SS'B|S'SS|B.SxBxSSxBxS|B..S//B/\\//S/\//!

Takes input in unary as 1s appended to the program. Produces output in unary as .s.

Try it online!

The program sends the ! to the end of the input, then makes several more substitutions. After completing the substitutions that exist in the initial program, each 1 from the input has been replaced with the following "1 code" (line breaks added for clarity):

/.\"/.\|\"/
/.\|/|./
/"\|/"/
/|\./x\x/
/x\x/|\../

and after that, /'//'.'.

Each copy of the "1 code" multiplies the number of full stops between the single quotes by 1, then increases the multiplier of the subsequent copies by 1. Many backslashes have been used to ensure that the rest of the code is not modified by earlier copies' execution.

The multiplication is done by adding a | at the end, then moving it left, replacing each . it passes with ., then removing it. To increase the multiplier, |. is changed to |.., with the intermediate step of xx.

Finally, the last substitution removes the single quotes, and the result is printed.

\$\endgroup\$
1
  • \$\begingroup\$ takes the factorial as unary input.... thats one of the most terrifying forms of input ive ever heard of, +1 \$\endgroup\$
    – des54321
    Apr 12, 2022 at 17:55
8
\$\begingroup\$

MAWP, 19 bytes

@[!1A]%_1A[%W_1A]~:

Try it!

\$\endgroup\$
3
  • \$\begingroup\$ F*** MAWP (Upvote) \$\endgroup\$ Aug 25, 2020 at 2:25
  • 3
    \$\begingroup\$ TooFast4Meeeeeee \$\endgroup\$
    – Razetime
    Aug 25, 2020 at 2:27
  • \$\begingroup\$ @Razetime Haha! \$\endgroup\$
    – lyxal
    Aug 25, 2020 at 2:28
8
\$\begingroup\$

TI-BASIC (TI-83), 2 bytes

Ans!

Takes input via Ans. The character count differs from the byte count because TI-BASIC is tokenised; Ans and ! are both 1-byte tokens.

Sample output

Uses this emulator.

enter image description here

\$\endgroup\$
8
\$\begingroup\$

Rattle, 23 20 bytes

|s>s[0+q][g-s<*~s>]~

Try it online!

This is the answer that I could not post on the other challenge! (see this)

Note that I do not have an online interpreter for Rattle yet so the interpreter is mashed together into the header on TIO (which is why TIO thinks it's Python 3 code but what's in the code section is only Rattle code - ignore the header and footer).

This actually works for up to 170! (but will a loss of precision, of course). In the next Rattle update this will actually become a builtin - making the possible solution just two bytes - but for its current version this is likely the shortest and most interesting factorial program.

Explanation

|           takes user's input
s>s         saves the input to memory slots 0 and 1
[0+q]       if the top of the stack is equal to zero: increments, and quits (implicitly prints the top of the stack)
[    ]~     loop n times, where n is the value in storage at the pointer
 g-s         gets the value at the pointer, decrements, and saves
 <           moves pointer left
 *~          pushes product of old top of stack and value at pointer to new top of stack
 s           saves to memory slot at pointer
 >           moves pointer right
             (implicitly outputs the value at the top of the stack after the program executes)

In essence, this program saves the given value (from input) to two memory slots. Then, it decrements one memory slot and multiplies the other by the decremented value, until the value decrements to 1, then it outputs the final value.

\$\endgroup\$
8
\$\begingroup\$

Java, 37 36 bytes

int f(int n){return n<2?1:n*f(n-1);}

I simply wanted to try to participate although Java is not the best language to have as little bytes as possible.

This is simply the definition coined to Java, with a recursive call.

edit: one byte less, thx @Jo King

\$\endgroup\$
1
  • 2
    \$\begingroup\$ You can also use a lambda expression to save more bytes. \$\endgroup\$
    – corvus_192
    Aug 27, 2020 at 9:55
8
\$\begingroup\$

Miniflak, 90 80 bytes

-10 bytes thanks to @Nitrodon!

{(({})[()])}{}((())){({(()[{}]({}))([{}]({}))}({}{})[{}])(({}({}))[({}[{}])])}{}

Try it online!

We already have another Brain-Flak answer here, but it uses both stacks and so doesn't work in Miniflak (a restricted subset of Brain-Flak where <, > and [] are disallowed). To avoid the second stack, this program uses a different multiplication algorithm.

Explanation

{(({})[()])}
{          }    # While the top of the stack is nonzero:
   {}           # Pop the stack
  (  )          # Push a copy on the stack
      [()]      # Subtract 1
 (        )     # Push the result

This part counts down from the input value to 0, leaving a copy of each number in order.


{}((()))
{}              # Pop the zero on the top
  ((()))        # Push 1 twice

These extra ones are there so that when the input is 0 or 1, we multiply them together to get 1 instead of accidentally multiplying something by 0.


{({(()[{}]({}))([{}]({}))}({}{})[{}])(({}({}))[({}[{}])])}{}
{                                                        }    # While the top of the stack is nonzero:
 ({(()[{}]({}))([{}]({}))}({}{})[{}])                         # Multiply the top two values
                                     (({}({}))[({}[{}])])     # Swap the top two values
                                                          {}  # Remove the zero on top

This loop is the core of the program: at each step, it multiplies the top two numbers together and then brings the number below them to the top. When we run out of numbers, a zero gets swapped to the top, and the loop ends. We then remove that zero, and the result of multiplying all the numbers together (which is the factorial of the input, as the numbers counted down from it to 1) is left.


How does this multiplication algorithm work?
(Suppose the top two numbers on the stack are a and b.)

({(()[{}]({}))([{}]({}))}({}{})[{}])
      {}                               # Pop a
     [  ]                              # Subtract it ... 
   ()                                  # ... from 1
         ({})                          # Add b
  (          )                         # Push the result
               [{}]                    # Subtract that ... 
                   ({})                # ... from b ...
              (        )               # and push the result
 {                      }              # Repeat until a reaches 0, keeping a running total of the sum of both results
                          {}{}         # Pop a and b, add them together, ... 
                         (    )[{}]    # ... and ignore the result
(                                  )   # Push the running total

During each run-through, a (the top of the stack) is replaced by b-(b+(1-a)), which equals a-1. This repeats until a reaches 0, so the number of iterations is equal to the first input. The running total keeps track of the sum of the two results at each iteration. The first result is b+(1-a) and the second is a-1, so their sum is always b, the second input. This means that keeping track of the running total yields the product of the two inputs. Finally, before pushing the product, we pop a and b because we don't need them anymore.

The last piece is the swapping algorithm:

(({}({}))[({}[{}])])
  {}                  # Pop the top number
    ({})              # Add the second number
 (      )             # Push the result
           {}         # Pop the sum
              {}      # Pop the second number ... 
             [  ]     # ... and subtract it from the sum
          (      )    # Push the result (the first number) ...
         [        ]   # ... and subtract that from the previous result (the sum)
(                  )  # Push the final result (the second number)

Since the first number is pushed back before the second one, their order is swapped from before.

\$\endgroup\$
1
7
\$\begingroup\$

JavaScript (Node.js), 17 bytes

y=x=>x?x*y(x-1):1

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Would y=x=>x*y(x-1)||1 work? \$\endgroup\$ Aug 25, 2020 at 0:12
  • 4
    \$\begingroup\$ That's what I originally tried, but it attempts to evaluate y(x-1) to see if it is true, leading to infinite recursion. \$\endgroup\$
    – Scott
    Aug 25, 2020 at 0:48
7
\$\begingroup\$

CJam, 4 bytes

rim!

Try it online

I'm sure there's other 4-bytes solutions, but I quite like how this makes an English word with punctuation, even if exclaiming "rim!" without context seems absurd.

\$\endgroup\$
6
\$\begingroup\$

QBasic, 37 bytes

INPUT n
f=1
FOR i=1TO n
f=f*i
NEXT
?f

If n is zero, the for loop does nothing and 1 is output. Otherwise, the for loop runs over i from 1 up to and including the input number, multiplying the result by each i.

The values here are single-precision by default, which means that after 10! we start getting output in scientific notation. The values are still accurate for 11! and 12!, though (e.g. 12! gives 4.790016E+08). At 13! we start to see rounding error (6.227021E+09 for 6227020800). If we use a double-precision variable f# in place of f (+4 bytes), we get accurate results up to 21!.

\$\endgroup\$
6
\$\begingroup\$

Rust, 20 bytes

|n|(1..=n).product()

Try it online!

\$\endgroup\$
6
\$\begingroup\$

Rust, 27 bytes

Closure that takes n as its input. Thanks to madlaina

|n|(1..=n).fold(1,|f,x|f*x)

Sample wrapper program to call closure (111 bytes).

fn main(){let f=|n|(1..=n).fold(1,|f,x|f*x);print!("{}",f(std::env::args().nth(1).unwrap().parse().unwrap()));}

Try it online!

Rust, 104 bytes

fn main(){print!("{}",(1..=std::env::args().skip(1).next().unwrap().parse().unwrap()).fold(1,|f,x|f*x))}

Try it online!

Rust sure isn't built for golfing, but 'twas interesting to do so! Takes n via program arguments. Conveniently fails at 13!

I'm certain a fair number of bytes can be shaved from this, possibly if the unwrap() calls can be eliminated using ? and a Result.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ codegolf.stackexchange.com/questions/74096/… \$\endgroup\$
    – Razetime
    Aug 25, 2020 at 11:12
  • \$\begingroup\$ Sorry, I didn't see your answer before posting my own. You don't have to write a full program, a closure is fine for these sorts of challenges. You can use .nth(1) instead of .skip(1).next(). It is possible to return a Result from main, but unfortunately there's no standard type unifying NoneError from the Option and ParseIntError (Box<dyn std::error::Error> doesn't work because it's not implemented by NoneError (and probably shouldn't be)). In any case, the signature overhead is larger than the few bytes saved in most cases. \$\endgroup\$
    – madlaina
    Aug 25, 2020 at 19:10
  • \$\begingroup\$ @madlaina Thank you! So that means I can use the function argument as input without taking it from program arguments I presume? Also I can't remember why I didn't use nth(), I guess I had issues with stdin, I'll change that too :) \$\endgroup\$ Aug 26, 2020 at 3:39
  • \$\begingroup\$ Yes, you can just take the inputs as closure arguments, and you don't have to print the result, returning it is fine in most cases. \$\endgroup\$
    – madlaina
    Aug 26, 2020 at 6:39
6
\$\begingroup\$

ArnoldC, 409 bytes

IT'S SHOWTIME
HEY CHRISTMAS TREE f
YOU SET US UP 1
HEY CHRISTMAS TREE x
YOU SET US UP 0
GET YOUR ASS TO MARS x
DO IT NOW
I WANT TO ASK YOU A BUNCH OF QUESTIONS AND I WANT TO HAVE THEM ANSWERED IMMEDIATELY
STICK AROUND x
GET TO THE CHOPPER f
HERE IS MY INVITATION f
YOU'RE FIRED x
ENOUGH TALK
GET TO THE CHOPPER x
HERE IS MY INVITATION x
GET DOWN 1
ENOUGH TALK
CHILL
TALK TO THE HAND f
YOU HAVE BEEN TERMINATED

Try it online!

Iterative approach, it just loops starting from the input number and decreasing it until it reaches 0.

\$\endgroup\$
6
\$\begingroup\$

convey, 16 bytes

 }>-1
1@"v
^*",{

Try it online!

Loops over the input value until it reaches 0. There may be a shorter way using the indices command (/.), but it seems to take up more logic than I want. Since the interpreter includes a handy-dandy gif maker, you can even see it in action.

!

\$\endgroup\$
5
\$\begingroup\$

Jelly, 1 byte

!

Try it online!

\$\endgroup\$
1
  • 11
    \$\begingroup\$ For once a Jelly program that I understand! :) \$\endgroup\$
    – 640KB
    Aug 28, 2020 at 14:17
5
\$\begingroup\$

J, 1 byte

!

Try it online!

Works for APL too

\$\endgroup\$
3
  • 1
    \$\begingroup\$ Also works in most, if not all, flavors of APL (which is the parent of J), and Jelly (which is a child of J). \$\endgroup\$
    – Bubbler
    Aug 24, 2020 at 23:29
  • 1
    \$\begingroup\$ Why not? After you made that explanation, I thought ! was for logical negation... \$\endgroup\$
    – user96495
    Aug 25, 2020 at 2:21
  • \$\begingroup\$ Ha. That would be -. \$\endgroup\$
    – Jonah
    Aug 25, 2020 at 2:22
5
\$\begingroup\$

R, 15 bytes

gamma(scan()+1)

There is also factorial which appears to be allowable as a 9-byte solution.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ or 15 bytes using scan() instead of function(x) \$\endgroup\$ Aug 25, 2020 at 9:11
  • \$\begingroup\$ factorial is the obvious shortest answer, but if you insist on a full program then prod(1:scan()) is 14 bytes. \$\endgroup\$ Aug 25, 2020 at 9:22
  • \$\begingroup\$ @Robin, that doesn't work for input 0. \$\endgroup\$
    – JDL
    Aug 25, 2020 at 9:27
  • \$\begingroup\$ Indeed, sorry about that. \$\endgroup\$ Aug 25, 2020 at 9:27
5
\$\begingroup\$

Pip, 5 bytes

$*\,q

Try it online!

\$\endgroup\$
0
5
\$\begingroup\$

Mini-Flak, 56 bytes

{(({}[()])({({}({}))[({}[({})()])]}{}{})[({})])}{}({}())

Try it online!

When golfing a fold operation in Brain-Flak, it is generally better to keep the stack small and use a "generator" than to push the entire list at once. I'm not exactly why this is true, but it typically works out that way. In this case, it avoids an entire swap operation, since the loop index can stay on top the whole time.

The other main optimization is to make the bottom of the stack equal the running total minus 1. This 1 has to be added back later, but this is shorter than pushing a 1 below the input at the beginning.

The multiplication algorithm here is a variant of the swap algorithm. Specifically, there are two equivalent swap algorithms: (({}({}))[({}[{}])]) calculates B as (A + B) - A, while (([{}]({}))([{}]{})) calculates B as (B - A) + A. To use this in a multiplication loop, we can modify these to not destroy B, and also decrement A by 1. There are three ways to add a single () to decrement A:

  • ([{}]()({}))([{}]({})) evaluates to B.
  • ([{}]({}))([{}()]({})) evaluates to B - 1
  • ({}({}))[({}[({})()])] evaluates to B + 1

The latter is what we want, since B is one less than the factor I actually want to represent. By multiplying A - 1 by B + 1 and then adding B, we obtain A(B+1) - 1 as desired.

# Running counter: A
# Running product: B+1

# Start main loop
{

  (

    # Subtract 1 from A
    ({}[()])

    # Multiply by B+1
    ({({}({}))[({}[({})()])]}

    # Add B to get A(B+1) - 1 and push
    {}{})

  # Cancel out product to push A-1 again
  [({})])

}{}

# Add 1 to get final result
({}())
\$\endgroup\$
5
\$\begingroup\$

Quipu, 64 bytes

\/1&1&0&2&
3&++[][][]
>>3&**1&/\
1&[]1&++
;;%%>>1&
3&4&1&??
??==

Try it online!

I decided to try out Quipu for LYAL event, and it's pretty fun to finagle with. I originally had this answer on the other factorial question, not realizing that it was invalid due to overflow.

Ungolfed:

"0  1  2  3  4 
---------------"
 \/ 1& 1& 0& 2&
 3& ++ [] [] []
 >> 3& ** 1& /\
 1& [] 1& ++
 ;; %% >> 1&
 3& 4& 1& ??
 ?? ==

Thread 0 takes input, then jumps to thread 3 if N > 0, otherwise it sets its value to 1 and jumps to thread 3.

Thread 3 then takes the value of thread 0 (N if N > 0, else 1) and increments it by 1 (we'll call this M), then jumps to thread 1.

Thread 1 increments its value, which acts as the accumulator (acc), and if acc == M, it jumps to thread 4, otherwise it jumps to thread 2.

Thread 2 takes its value (X) and multiplies it by acc. If X != 0, it jumps back to thread 1, otherwise it sets X to 1 and jumps to thread 3.

Once acc reaches M, execution jumps to thread 4, which prints the value of thread 2.

\$\endgroup\$
5
+150
\$\begingroup\$

Prolog (SWI), 61 bytes

0+1.
N+F:-nth1(N,_,_),Y is N-1,Y+G,(F is G*N->1>0;F<G,!,0>1).

Try it online!

Steffan's answer is much shorter at 28 bytes, but this predicate was created to be as general as possible. It can be used to:

  • Validate that N! = F (for example, 5+120 will succeed, 6+120 will fail)
  • Calculate N! (5+F will bind F to 120)
  • Calculate N from N! (N+120 will bind N to 5)
    • N+1 has both 0 and 1 as possible values
    • A non-factorial will fail the predicate
  • Generate all N, N! pairs

The last section feels like it can be golfed, especially as it has both 0>1 as always true and 0<1 as always false, but I've been staring at it for a while and can't figure out anything better. Pity that \+! doesn't work.

\$\endgroup\$
2
  • \$\begingroup\$ what's the nth1 for btw? \$\endgroup\$
    – ASCII-only
    May 7 at 8:00
  • \$\begingroup\$ @ASCII-only That's for iterating over each possible value of N>0 to make it more generalised . If N is already given (as it is in this challenge), that just evaluates as true. \$\endgroup\$
    – Jo King
    May 7 at 21:57
5
\$\begingroup\$

TypeScript Type System, 98 99 bytes

type X<A,B=A>=B extends`1${infer R}`?R extends""?A:B extends A?X<B,X<R>>:`${A&string}${X<R,A>}`:"1"

Try it at the TypeScript playground

+1 byte to make X<0> work properly

I/O is unary strings.

Go check out emanresu A's really clean golf of this! It uses pretty much the same formula but the execution is really great.

It took me a little over an hour to come up with and golf. It's pretty hard to explain but the gist of it is that X<A> does the factorial, and X<A,B> does multiplication. It figures out which is being used by making B default to A if not specified, and checking if B extends A. I was able to get it so short by combining the types for factorial and multiplication, since they shared a lot of boilerplate.

I also wrote a version that uses decimal I/O for 184 175 bytes:

//@ts-ignore
type X<A,B=[]>=A extends 1[]?B extends[1,...infer R]?R extends[]?A:B extends A?X<A,X<R,R>>:[...A,...X<R,A>]:[1]:B extends{length:A}?X<B,B>["length"]:X<A,[...B,1]>

Try it at the TypeScript playground

@tjffvi showed me this spectacular 153 byte version with I/O in decimal:

//@ts-ignore
type M<A,B,N=[]>=A extends[0,...infer A]?M<A,B,[...N,...B]>:N;type F<N,X=[],A=[0],L="length">=X[L]extends N?A[L]:F<N,[0,...X],M<[0,...X],A>>

Try it at the TypeScript playground

\$\endgroup\$
3
  • 1
    \$\begingroup\$ fails for n=0 \$\endgroup\$
    – ASCII-only
    May 7 at 5:16
  • 1
    \$\begingroup\$ hotfix, 113 \$\endgroup\$
    – ASCII-only
    May 7 at 5:17
  • \$\begingroup\$ @ASCII-only fixed for only 1 byte :D \$\endgroup\$
    – noodle man
    May 7 at 11:24
4
\$\begingroup\$

Brain-Flak, 52 bytes

<>(())<>{(({}[()]))({<>({})<><({}[()])>}{}<>{})<>}<>

Try it online!

Posting my own Brain-Flak solution, which differs from the same size one from the older challenge.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ You might want to move your Brainfuck answer too, as BF can't meet the performance requirement of the old challenge (which makes all BF answers there invalid). \$\endgroup\$
    – Bubbler
    Aug 25, 2020 at 1:20
1
2 3 4 5

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.