39
\$\begingroup\$

Not to be confused with Find the factorial!

Introduction

The factorial of an integer n can be calculated by $$n!=n\times(n-1)\times(n-2)\times(...)\times2\times1$$

This is relatively easy and nothing new. However, factorials can be extended to double factorials, such that $$n!!=n\times(n-2)\times(n-4)\times(...)\times4\times2$$ for even numbers, and $$n!!=n\times(n-2)\times(n-4)\times(...)\times3\times1$$ for odd numbers. But we're not limited to double factorials. For example $$n!!!=n\times(n-3)\times(n-6)\times(...)\times6\times3$$ or $$n!!!=n\times(n-3)\times(n-6)\times(...)\times5\times2$$ or $$n!!!=n\times(n-3)\times(n-6)\times(...)\times4\times1$$ depending on the starting value.

In summary: $${\displaystyle n!^{(k)}={\begin{cases}1&{\text{if }}n=0 \\n&{\text{if }}0<n\leq k\\n\cdot\left({(n-k)!}^{(k)}\right)&{\text{if }}n>k\end{cases}}}$$ where $${\displaystyle n!^{(k)}=n\underbrace{!\dots!}_{k}}$$ Or, in plain English: Subtract the factorial count from the base number repeatedly and multiply all resulting positive integers.

The Challenge

Write a function that will calculate any kind of repeated factorial for any non-negative integer.

Input

Either

  • A string containing a non-negative base-ten integer, followed by 1 or more exclamation marks. E.g. "6!" or "9!!" or "40!!!!!!!!!!!!!!!!!!!!".

or

  • The same values represented by two integers: one non-negative base value and one positive value representing the factorial count. This can be done according to any format from the default I/O rules.

Output

The result of said calculation.

Challenge remarks

  • 0! equals 1 by definition. Your code must account for this.
  • The factorial count is limited by $$ 0 < factorial~count \leq base~value $$outside this range, you are free to output whatever. Aside from 0!, which is the only exception to this rule.

Examples

Input Output 3!!! 3 0! 1 6! 720 9!! 945 10!!!!!!!! 20 40!!!!!!!!!!!!!!!!!!!! 800 420!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 41697106428257280000000000000000 

Try it with an ungolfed Python implementation: Try it online!

General remarks

\$\endgroup\$
8
  • 7
    \$\begingroup\$ The examples list 0! but the challenge remarks say that the factorial count will be less than or equal to the base value. \$\endgroup\$ Commented Aug 5, 2019 at 13:09
  • 1
    \$\begingroup\$ Wouldn't 3!!! be zero? n*(n-3) = 3*(3-3) = 0. \$\endgroup\$ Commented Aug 5, 2019 at 13:31
  • 2
    \$\begingroup\$ @ouflak If it works like 1!, not really. It's more like 1! = 1. 2!! = 2. 3!!! = 3. There's no calculation, because you are at the end of the recursiveness. No 0 in products or else every single factorial would drop down to 0 in the end. \$\endgroup\$ Commented Aug 5, 2019 at 14:16
  • 4
    \$\begingroup\$ 3!!!!!!! should not be undefined—it should just yield the answer 3. It's the same as 1!!=1 (not undefined). Also your input specification says that there will always be at least one !, so the first example 3 doesn't fit the specification. \$\endgroup\$ Commented Aug 5, 2019 at 18:04
  • 4
    \$\begingroup\$ @FabianRöling: But that's not what this is. It's not (3!)! instead it's removing terms from a factorial. It's a misleading name; I came in assuming it was going to be applying the Factorial function repeatedly in a chain and had to read carefully to see what it actually was. Fortunately the question does explain it clearly. A better name might be stride factorial or step factorial or something. \$\endgroup\$ Commented Aug 8, 2019 at 5:31

42 Answers 42

1
2
1
\$\begingroup\$

JavaScript (Node.js), 35 bytes

(n,i,f=i)=>i-n<1?f:r(n,i-n,f*(i-n)) 

Try it online!

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

Forth (gforth), 50 bytes

: f 1 1 2over / 1+ 0 do 2over i * - 1 max * loop ; 

Try it online!

Code Explanation

: f \ start a new word definition 1 1 \ add placeholder and accumulator to stack 2over / 1+ \ get the number of times to run the loop (num/factorial + 1) 0 do \ start loop from 0 to num/factorial 2over \ copy num and factorial to the top of the stack i * - \ get the current number to multiply by (num - factorial * i) 1 max \ make sure it can't be 0 or negative [set to 1 if it is] * \ multiply accumulator by result loop \ end loop ; \ end the word definition 
\$\endgroup\$
1
\$\begingroup\$

Perl 5 -Mbigint -p, 45 bytes

$b=s/!//g;$\=1*$_||1;$\*=$_ while($_-=$b)>0}{ 

Try it online!

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

Stax, 6 bytes

å▐█ΩV∟ 

Run and debug it

It takes input in the form {count} {base}.

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

Gaia, 6 bytes

…)¦v%Π 

Try it online!

Takes input as n, k, so input of 3 4 would be 3!!!!.

…	 push [0...n-1], or [] if n == 0 )¦	 increment each value (does nothing if []) v	 reverse list %	 take every k'th element Π	 product; product([]) = 1.
\$\endgroup\$
1
\$\begingroup\$

Bash + coreutils, 27

seq -s\* $[$1+!$1] -$2 1|bc 

Try it online!

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

PHP, 47 bytes

Recursive function with tests

function f($n,$c){return$n>0?f($n-$c,$c)*$n:1;} 

Try it online!


PHP, 54 bytes

Loop version (original answer)

for($n=$argv[1],$f=1;$n>0;$f*=$n,$n-=$argv[2]);echo$f; 

Try it online!


First argument is the the base value and second one is the factorial count.

Supports specified valid range, but outputs big numbers in scientific notation. For example the last sample is shown as 4.1697106428257E+31.

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

Lua, 150 145 129 bytes

i=io.read()p,c=i.gsub(i,"!","")p=p+0 function f(n,c)r=1 if n~=0 then while(n>0) do r=r*n n=n-c end end return r end print(f(p,c)) 

Try it online!

Ported from Charlie's ArnoldC psuedocode. -16 bytes thanks to Charlie

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can submit only the function as answer, which can also be improved. \$\endgroup\$ Commented Aug 6, 2019 at 17:13
  • \$\begingroup\$ @Charlie, Yeah when I get more comfy with the idea of headers and footers in TIO, I'll experiment a bit more. \$\endgroup\$ Commented Aug 7, 2019 at 6:32
1
\$\begingroup\$

Python 3 (Input as string), 82 bytes

m=lambda n,s:n<1or n*m(n-s,s) f=lambda x:int(m(int(x.split("!")[0]),x.count("!"))) 

Try it online!

Note: the outer int() in f is solely for the fact that without it, 0! will output True

\$\endgroup\$
1
  • \$\begingroup\$ Nice approach! True == 1 in Python, so without conversion it is still valid. \$\endgroup\$ Commented Aug 8, 2019 at 5:35
1
\$\begingroup\$

Regex 🐇 (RME / PCRE2 v10.35+), 25 bytes

^(x+),((?*x+)(?>\1|.*))*$ 

Attempt This Online! - PCRE2
Try it on replit.com! - RegexMathEngine, in ECMAScript+(?*)+(?>) mode

Takes its input in unary, as two strings of x characters whose lengths represent the numbers, in the order {factorial count, base value}, joined/delimited by a ,. Returns its output as the number of ways the regex can match. (The rabbit emoji indicates this output method.)

^(x+), # \1 = input factorial count; tail = input base value ( (?*x+) # Assert tail > 0; multiply the number of possible matches by tail (?> # Atomic group – lock in this match once it's finished \1 # tail -= \1 | # or .* # tail = 0 ) )* # Iterate the above as many times as possible, minimum zero $ # Assert tail == 0 

Regex 🐇 (RME / PCRE2 v10.35+), 26 bytes

^((?=(x*).*,\2)(?*x+)\2)*, 

Attempt This Online! - PCRE2
Try it on replit.com! - RegexMathEngine, in ECMAScript+(?*) mode

Takes the two numbers in the order {base value, factorial count}. Although this is 1 byte longer, it does not need an atomic group to be this length, using an atomic lookahead instead.

^ # tail = input base value ( (?= # Atomic lookahead (x*) # \2 = maximum value ≤ tail for which the following matches: .*, # tail = input factorial count \2 # Assert tail ≥ \2 ) (?*x+) # Assert tail > 0; multiply the number of possible matches by tail \2 # tail -= \2 )* # Iterate the above as many times as possible, minimum zero , # Assert tail == 0 
\$\endgroup\$
1
\$\begingroup\$

Thunno 2, 5 bytes

RrẈhp 

Try it online!

Explanation

RrẈhp # Implicit input Rr # Push the range [n..1] Ẉ # Uninterleave into k pieces hp # Product of first group # Implicit output 
\$\endgroup\$
1
\$\begingroup\$

C (gcc), 26 bytes

f(b,c){b>c?b*=f(b-c,c):0;} 

Simple recursive implementation:

int f(int base, int count) { return base > count ? base * f(base-count, count) : b; } 

There are equivalent expressions of the same length, e.g.:

f(b,c){b*=b>c?f(b-c,c):1;} 

Try it online!

\$\endgroup\$
1
2

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.