39
\$\begingroup\$

Write a program or function that finds the number of zeroes at the end of n! in base 10, where n is an input number (in any desired format).

It can be assumed that n is a positive integer, meaning that n! is also an integer. There are no zeroes after a decimal point in n!. Also, it can be assumed that your programming language can handle the value of n and n!.


Test cases

1
==> 0

5
==> 1

100
==> 24

666
==> 165

2016
==> 502

1234567891011121314151617181920
==> 308641972752780328537904295461

This is code golf. Standard rules apply. The shortest code in bytes wins.

\$\endgroup\$
10
  • \$\begingroup\$ Related. \$\endgroup\$
    – xnor
    May 12 '16 at 2:39
  • \$\begingroup\$ Can we assume that n! will fit within our languages' native integer type? \$\endgroup\$
    – Alex A.
    May 12 '16 at 2:45
  • \$\begingroup\$ @AlexA. Yes you can. \$\endgroup\$
    – Arcturus
    May 12 '16 at 3:01
  • \$\begingroup\$ Can n be an input string? \$\endgroup\$ May 12 '16 at 3:10
  • 17
    \$\begingroup\$ I think this would be a better question if you were not allowed to assume n! would fit into your integer type! Well, maybe another time. \$\endgroup\$
    – A Simmons
    May 12 '16 at 10:45

60 Answers 60

1
2
1
\$\begingroup\$

J, 7 bytes

Monadic function, taking argument on the right.

3{:@q:!

If x is positive, x q: y returns the exponents in a prime factorization of y, for only the first x primes. The 3-rd prime is 5 and {: takes the tail of a list.

Note that you have to input integers with an x at the end, or else J will treat them as floats.

   3{:@q:! 100x
24
   3{:@q:! 666x
165
   3{:@q:! 2016x
502

Try it yourself at tryj.tk, though be warned that this online interpreter will complain if you try anything larger than 1343.

If you want something that doesn't compute n! and hence doesn't require it fit in an integer, use the recursive solution <.@%&5(+$:@)^:*. (tryj.tk is still whiny on large inputs.)

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

Ruby, 70 61 51 49 bytes

Version 3 with thanks to Kenny Lau and daniero

->n{(n-n.to_s(5).chars.map(&:to_i).reduce(:+))/4}

Edit: Turns out you can save two bytes by mapping to_i before you reduce. Weird :P

This function subtracts the sum of n's base 5 digits from n and then divides that result by 4. This is related to the sum of the geometric series 1+5+25+..+5**n = (5**n+1)/4.

As an example (again, with thanks to Kenny Lau), consider 358 (2413 in base 5) minus its base 5 digits.

2413-2-4-1-3 
= (2000-2) + (400-4) + (10-1) + (3-3)
# consider that 1000-1=444 and you'll see why every 5**n is multiplied by 4
= 2*444 + 4*44 + 1*4 + 3*0
= 2*(4*5**0+4*5**1+4*5**2) + 4*(4*5**0+4*5**1) + 1*(4*5**0) + 3*()
= 348

Divide 348 by 4 and you get f(358) = 87.

Version 2 with thanks to Kenny Lau

->n{s=(1..n).reduce(:*).to_s;s.size-s.reverse.to_i.to_s.size}

This function calculates n! then subtracts the size of n! from the size of (n!).reverse.to_i.to_s, which removes all the zeroes, thus, returning the size of the zeroes themselves.

Version 1

->n{s=n.to_s(5).chars;(0...s.size).reduce{|a,b|a+(s[0,b]*'').to_i(5)}}

This a variation of the "How many 5s are there in the prime factorization of n!?" trick that uses Ruby's simple base conversion builtins.

The golfing is a bit of a pain though, with converting from Integer to String to Array, grabbing part of the Array and converting that to String to Integer again for the reduce. Any golfing suggestions are welcome.

\$\endgroup\$
2
  • \$\begingroup\$ It's slightly shorter to map to_i before reducing: ->n{(n-n.to_s(5).chars.map(&:to_i).reduce(:+))/4} (saves two bytes) \$\endgroup\$
    – daniero
    May 16 '16 at 16:21
  • \$\begingroup\$ @daniero I would not have expected that. Thanks :D \$\endgroup\$
    – Sherlock9
    May 16 '16 at 17:37
1
\$\begingroup\$

Dyalog APL, 9 bytes

⊥⍨'0'=⍕!⎕

prompt for number

! factorialize

stringify

'0'= check equality to character zero

⊥⍨ count trailing trues*


*Literally it is a mixed-base to base-10 conversion, using the boolean list as both number and base:

⊥⍨0 1 0 1 1 is the same as 0 1 0 1 1⊥⍨0 1 0 1 1 which is 0×(0×1×0×1×1) 1×(1×0×1×1) 0×(0×1×1) 1×(1×1) + 1×(1) which again is two (the number of trailing 1s).

\$\endgroup\$
2
  • \$\begingroup\$ It's difficult to get myself in the headspace of APL. I'm just so used to low level imperative languages. This was my attempt {+/⌊⍵÷5*⍳⌊5⍟⍵}. Also, I feel like there should be a way to make a train out of this, but I just can't see it. \$\endgroup\$ Mar 12 at 4:26
  • \$\begingroup\$ @1_am_Jack The consecutive monadic functions are problematic: +/∘⌊⊢÷5*∘⍳∘⌊5⍟⊢ or +/⌊⍤÷5*5⍳⍤⌊⍤⍟⊢ or some hybrid of those ― Some resources here: apl.wiki/Tacit_programming#Tutorials \$\endgroup\$
    – Adám
    Mar 12 at 5:57
1
\$\begingroup\$

Pyt, 5 bytes

5←!ḋɔ

Explanation:

5             Pushes 5
 ←            Gets input
  !           Factorial
   ḋ          Prime factors (with duplicates)
    ɔ         Count occurrences of 5 in the list of prime factors

Try it online!

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

J, 15 bytes

+/<.(%5:^>:@i.)

Who needs to calculate factorial?

Probably longer than with though :p

Explanation when I get home

\$\endgroup\$
1
  • \$\begingroup\$ (%5:^>:@i.) -> (%5^1+i.) \$\endgroup\$
    – FrownyFrog
    Jan 4 '18 at 3:06
1
\$\begingroup\$

Runic Enchantments, 21 bytes

Rl1)?@+
/:>i5,'fA:0)?

Try it online!

Uses the same f(n) = n/5 + f(n/5) as other answers. Just took some coercion to to reduce the footprint as much as possible. Fortunately > does nothing when executed (it simply marks the entry point) and i pushes nothing to the stack when no more input remains.

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

Python 2, 33 bytes

f=lambda n:n/5+f(n/5)if n>0else 0

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Wow, I had no idea Python could parse out the >0 like that. \$\endgroup\$ Aug 17 '20 at 19:37
  • \$\begingroup\$ @Calculuswhiz It's pretty cool, although I think it no longer works in Python 3. \$\endgroup\$ Mar 16 at 11:49
1
\$\begingroup\$

05AB1E, 4 bytes

!Ò5¢

Try it online!

!Ò5¢  # full program
   ¢  # number of...
  5   # literal...
   ¢  # s in...
 Ò    # prime factorization of...
!     # factorial of...
      # implicit input
      # implicit output
\$\endgroup\$
0
\$\begingroup\$

CJam, 9 bytes

l~m!mf5e=

Try it online!

Just counting the 5's 5e= in the prime factorization mf of the factorial m! of the input l~.

Doesn't work for big factorials, since they don't fit into an integer.

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

C, 53 bytes

 i,r;z(n){for(;i=n--;)for(;i=i%5?0:i/5;)r++;return r;}

Counting 5s in the sequence that makes up the factorial, instead of calculating the factorial and then counting its 5s.

Full program:

i,r;z(n){for(;i=n--;)for(;i=i%5?0:i/5;)r++;return r;}
#include <stdio.h>
int main(int argc, char **argv) {
    int n;
    sscanf(argv[1], "%d", &n);
    printf("%d -> %d\n", n, z(n));
    return 0;
}
\$\endgroup\$
0
\$\begingroup\$

Convex, 6 bytes

¡mf5e=

Use Java interpreter or this alternate version that works on TIO: Try it online

This would be 4 bytes if I was finished getting rid of 2 char operators....

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

PowerShell v2+, 60 bytes (but see the NB below)

A completely different approach, doing exactly what is requested by the challenge. ;-)

$a=2..$args[0]-join'*'|iex;"$a".length-"$a".Trim('0').length

Takes input $args and creates a dynamic range .., then -joins it together with * for multiplication, pipes that to iex (similar to eval) to compute the factorial. Store that in $a.

We then take the length of the string representation and subtract off the length of the string representation after we've passed it to .Trim('0') which will remove leading and trailing zeroes. Since there will never be leading zeroes, this gets us the result we want.

NB: The above will work for up to n=17 without a problem, as even though 17! is bigger than [Int]::MaxValue, since we didn't explicitly specify the casting for $a, PowerShell will dynamically convert it to [double] for us upon overflow. Yeah ... in PowerShell, [int] will overflow to [double] if not explicitly cast. No, I don't know why it goes to that rather than [int64].

However, at 18!, PowerShell will automatically convert the number to scientific notation when the implicit .ToString() is called (i.e., when encapsulating it within quotes), in order to preserve significant digits. We can get around that with explicit formatting instead -- $a="{0:0}"-f(2..$args[0]-join'*'|iex);$a.length-$a.Trim('0').length -- at 67 bytes. That will get us up to 20! before we start to run into loss of precision.

Thus, to handle an "arbitrary" input, we'll need to combine the above explicit formatting with the [bigint] datatype ...

PowerShell v2+, 80 bytes

$a="{0:0}"-f("[bigint]"+(2..$args[0]-join'*')|iex);$a.length-$a.Trim('0').length

This will prepend an explicit cast of [bigint] to the first number in the range 2, and in PowerShell the datatype on the left of the operator is used for output, so that [bigint] datatype will continue through the rest of the factorial calculation.


An few examples of the three methods at some key points, with some additional output text showing what's happening in the background -- the first output is the top code, the middle is with the explicit string formatting, and the bottom is with the [bigint] datatype.

PS C:\Tools\Scripts> .\golfing\zeroes-at-end-of-factorial.ps1 17
(Normal) 355687428096000 = 3
(Format) 355687428096000 = 3
(BigInt) 355687428096000 = 3

PS C:\Tools\Scripts> .\golfing\zeroes-at-end-of-factorial.ps1 18
(Normal) 6.402373705728E+15 = 0
(Format) 6402373705728000 = 3
(BigInt) 6402373705728000 = 3

PS C:\Tools\Scripts> .\golfing\zeroes-at-end-of-factorial.ps1 21
(Normal) 5.10909421717094E+19 = 0
(Format) 51090942171709400000 = 5
(BigInt) 51090942171709440000 = 4

PS C:\Tools\Scripts> .\golfing\zeroes-at-end-of-factorial.ps1 100
(Normal) 9.33262154439441E+157 = 0
(Format) 933262154439441000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000 = 143
(BigInt) 933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000
00000000 = 24

PS C:\Tools\Scripts> .\golfing\zeroes-at-end-of-factorial.ps1 666
(Normal) Infinity = 0
(Format) Infinity = 0
(BigInt) 101063205684078149339082270812987645175758239832414541134042080735741380210369702298920280680149101204098980220355752703933970405713072930283454242384
016585642874066153029797241068282869939717688434251350949378748077490349338925526287834176188326189942648494465716169313138031111761957305152642332038964180541
081606760789306748325981681536460982866866274811038560365797328460484207809414155642770874534510059882948847250594907196772727091196506088520929434066550648022
642608335790150309778114083249701373807911277761571911620331754219999948922714475266708579675248268885046126373228453917614236582397369676453760327876932228670
885547506983568164371084614056976933006577541441308350104365957229945444651724282400214055514046429629100190143841467573055296491456926973403850076414055114364
283612861330473414734808609512385966092678846067118146921625221337465049955783174195059482714722569989641408869425126104519667256749553222882671938160611697400
311264211156133257350321296072971178199390387741639438171846476552757501425212904028323696392262434445697502405816736843180906854457725847298397943781807264821
360865009874936976105696120379126536366566469680224519996204004154443821032721047698220334845859609307929656956126740947391412413210205581149373619966878853487
232170536051130524871079644147921335454258357607659625021345466796883799602327316306909470042946710666392541958119313633986054565867362395523193239940480940410
876723200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000 = 165
\$\endgroup\$
0
\$\begingroup\$

dc, 26

?[5/dd0<m]dsmx[+z1<m]dsmxp
\$\endgroup\$
0
\$\begingroup\$

rs, 95 bytes

(\d+)/(_)^^(\1)
_(_+)/_\1 \1
+_(_+) _(_+)$/(_\1)^^((^^_\2)) \2
 _$/
(_+)/(^^\1)
.*?(0*)$/(^^\1)

Live demo.

Note that I can't test this with large inputs such as 100. Feel free to try it, but you'd need over 8.486e145 TB of RAM...

An explanation of the first 5 lines is available here. The last line just counts the zeroes at the end.

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

CJam, 11

Efficient solution, similar to other answers.

Loop version:

ri{5/_}h]:+

Try it online

Explanation:

ri      read the input and convert to integer
{…}h    do…while
  5/    divide by 5
  _     duplicate the last number
         the loop terminates when the number reaches 0
]:+     add all the numbers from the stack

Recursive version:

ri0{5/_j+}j

Try it online

Explanation:

ri       read the input and convert to integer
0{…}j    calculate with memoized recursion and initial value 0 for input 0
  5/     divide by 5
  _      duplicate the result
  j      calculate the number of zeros recursively for that number
  +      add the 2 results
\$\endgroup\$
0
\$\begingroup\$

PHP, 62 bytes

for($n=$z=0;++$n<=log(125,5);){$z+=floor(125/(5**$n));}echo$z;
exploded view
for ($n=$z=0; ++$n<=log(125,5); ) {
  $z += floor( 125 / (5 ** $n) );
}
echo $z;

The starting point for many of the answers here is that every 5th factor adds a single 0, since there are 2-3 even numbers that precede it, and you can only get a new 0 with both a factor of 2 and a factor of 5.

If we assumed this to be true, the answer is simple in PHP, in 23 bytes:

echo(floor(argv[0]/5));

However, consider 25!. 24! has 4 0's in it (because of 5, 10, 15, and 20). But 25 adds two 5's to the equation, meaning 25! has 6 0's in it. So we have to account for 5^n as well.

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

GNU coreutils, 34 bytes

seq $1|factor|tr \  \\n|grep -cx 5

The set of prime factors of the factorial n! is the union of the sets of prime factors of 1..n. We just need to count the number of fives, as this will always be less than the number of twos, and it takes one five and one two to produce each trailing zero. Luckily, we don't need to deal with n==0 (would the solitary zero count as 'trailing'?)

The output of factor is not quite what we want (in fact, in every golf I do, the reprinting of input is a nuisance):

$ seq 6|factor
1:
2: 2
3: 3
4: 2 2
5: 5
6: 2 3

By replacing each space with a newline, we can match lines that are exactly 5 (this handily eliminates the 5: prefix for that line), and count the total.

You will probably run out of memory and/or time trying the last of the example inputs, but there's nothing in the program itself that wouldn't work.

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

Erlang, 33 bytes

f(0)->0;f(N)->N div 5+f(N div 5).

Same tactic as in xnor and Cᴏɴᴏʀ O'Bʀɪᴇɴ's answers.

Ungolfed:

f(0) -> 0;
f(N) when N > 0 -> N div 5 + f(N div 5).
\$\endgroup\$
0
\$\begingroup\$

bc, 51 bytes

define f(x){if(x){return x/5+f(x/5)}else{return 0}}

Same tactic as in xnor and Cᴏɴᴏʀ O'Bʀɪᴇɴ's answers, but longer.

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

GML, 35 bytes

a=argument0 while a/=5b+=a return b
\$\endgroup\$
0
\$\begingroup\$

Japt, 6 bytes

Can only handle inputs up to 21 due to JavaScript's integer limitations.

Êk xv5

Try it


Explanation

Ê          :Factorial
 k         :Prime factors
   v5      :Divisible by 5?
  x        :Reduce by addition
\$\endgroup\$
0
\$\begingroup\$

PHP, 43 39 bytes

based on Toby Speight´s C solution

function f($n){return$n?f($n/=5)+$n|0:0;}

Try it online.

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

Stax, 4 bytes

╩+Pî

Run and debug it

I omitted the final test case. The algorithm is correct, but the time requirements are beyond my patience or predicted lifespan.

Method:

  1. Compute factorial
  2. Calculate "multiplicity" by 10.
\$\endgroup\$
0
\$\begingroup\$

Forth (gforth), 38 bytes

Based on Toby Speight's C Solution

: f dup 0> if 5 / dup recurse + then ;

Try it online!

Code Explanation

: f           \ start a new word definition
  dup 0> if   \ check if n > 0
    5 / dup   \ divide by 5 and duplicate if so
    recurse   \ call f on n/5
    +         \ add to sum
  then        \ end if
;             \ end word definition
\$\endgroup\$
0
\$\begingroup\$

Keg, -rR, 9 bytes

0&¡÷{0=|⑹

Try it online!

I'm sure there is a more efficient way by using some sort of formula, but a counting method was the best I could think of.

Explained

0&¡÷{0=|⑹
0&          #Store 0 in the register
  ¡÷        #Take the factorial of the (implicit) input and item split
    {0=     #While the top item is still 0:
       |⑹  #    Increment the register
            #-rR prints the register as an integer at end of execution
\$\endgroup\$
0
\$\begingroup\$

naz, 10 bytes

1r3s5d9s1o

Try it online!

The maximum factorial that naz could technically store is \$5!\$ (120), so being allowed to assume that \$n!\$ will fit within our language's integer type paves the way for a very boring answer.

We first read \$n\$ from the input string, which sets the register to \$n\$'s ASCII value \$k\$. The number of zeroes at the end of \$n!\$ is then given by:

$$\lfloor(k - 3) / 5\rfloor - 9$$

The only value of \$k\$ that will result in a value of \$1\$ is \$53\$, which corresponds to \$n = 5\$.

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

Lua, 48 bytes

function u(x)return x>0 and x//5+u(x//5)or 0 end

Try it online!

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

AWK, 34 bytes

{i=$0;for($0=0;i;)$0+=i=int(i/5)}1

Ungolfed:

{i=$0;for($0=0;i;)$0+=i=int(i/5)}1
{                               }   for each line
 i=$0;                                save it in i
          $0=0;                       set output to 0
      for(     i;)                    while i is nonzero
                        int(i/5)        divide i by 5 without reminder
                      i=                save the result in i
                  $0+=                  and add it to output
                                 1    print output

Try it online!

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

Risky, 6 bytes

!!?+_0__/\\?

Try it online!

Explanation

! length
!       factorial
?         input
+     +
_
0         0
_   apply function
_
/         5
\     find indices in
\       prime factors
?         argument
\$\endgroup\$
0
\$\begingroup\$

asm2bf, 32 bytes

@f
divr1,5
addr2,r1
jnzr1,%f
ret

Resulting brainfuck code (~500 bytes):

+>+[<[>-]>[>]>+<<<[>>>[-]<-<<-]+>>+[-<[>+>-<<-]>>[<<<->>[<+
>>+<-]>[-]]<[-]]<<[>>+<<-]>>[-<<+>>>>>>>>>+++++[>>>>+<<<<-]
<<<<[>>>>>>>+>-[>>]<[[>+<-]<+>>>]<<<<<<<<<-]>>>>>>[<<<<<<+>
>>>>>-]>[<<<+>>>-]>[<<<<+>>>>-]<<<<[-]<<<<[>+<<+>-]<[>+<-]>
>>>>+<<<<[<<<<<[-]>>>>>>>>>[<<<<<<<<+>+>>>>>>>-]<<<<<<<[>>>
>>>>+<<<<<<<-]>>>[<<<+>>>-]]<<<[>>>+<<<-]>>>>>>>[-]<<<<<<<]
<<[>>+<<-]>>[-<<+[-]>[-]>>>>>>>>>>>>>>>>>>>>>[>>]<<->[<<<[<
<]<<<<<<<<<<<<<<<<<<<+>>>>>>>>>>>>>>>>>>>>>[>>]>-]<<<[<<]<<
<<<<<<<<<[-]<<<<<<<]<<[>>+<<-]>>[-<<+>>]<]

Extras

If you want to test the algorithm, you can use the following driver code. The code expects r1 to be the input number and leaves the output in r2, assuming r2 is already cleared:

movr1,666
@f
divr1,5
addr2,r1
jnzr1,%f
outr1

The resulting value might be outputted as an ASCII character, so you might have to use bfi fac.b | xxd to see the numerical value.

Optimizing for brainfuck source code size

We can optimize the code a fair bit. Since brainfuck has no notion of procedures, we can assume that @f is a while loop label (instead of being both a function and a normal label) and that we don't have to return.

The jnz instruction and the accompanying label can be replaced with a sequence of nav r1 / raw .[ or .]. To top it off, we use the -t flag for bfmake. The result:

>>>[>>>>+++++[>>>>+<<<<-]<<<<[>>>>>>>+>-[>>]<[[>+<-]<+>>>]<<<<<<<<<-]>>>>>>[<<<<<<+>>>>>>-]>[<<<+>>>-]>[<<<<+>>>>-]<<<<[-]<<<<[>+<<+>-]<[>+<-]>]

... at 144 bytes.

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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