Distribution of 0 digits in factorial series: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|Pascal}}: delete unused arrays, reorder, more comments)
Line 389: Line 389:
First ratio < 0.16 47332 0.15999999579985665
First ratio < 0.16 47332 0.15999999579985665
Real time: 4.898 s CPU share: 99.55 % // 2.67s on 2200G freepascal 3.2.2</pre>
Real time: 4.898 s CPU share: 99.55 % // 2.67s on 2200G freepascal 3.2.2</pre>

=={{header|Phix}}==
Using "string math" to create reversed factorials, for slightly easier skipping of "trailing" zeroes,
but converted to base 1000 and with the zero counting idea from Pascal, which sped it up threefold.
<!--<lang Phix>(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">rfs</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- reverse factorial(1) in base 1000</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">init_zc</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">zc</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">999</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">9</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- 00x</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- 0x0</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">100</span><span style="color: #0000FF;">*</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span> <span style="color: #000080;font-style:italic;">-- x00</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">10</span> <span style="color: #008080;">to</span> <span style="color: #000000;">90</span> <span style="color: #008080;">by</span> <span style="color: #000000;">10</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- 0yx</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- y0x</span>
<span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">10</span><span style="color: #0000FF;">*(</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">x</span><span style="color: #0000FF;">)]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- yx0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">zc</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">zc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">init_zc</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">trail</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()=</span><span style="color: #004600;">JS</span><span style="color: #0000FF;">?</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">:</span><span style="color: #000000;">50000</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">d999</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">trail</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">trail</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">l</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">or</span> <span style="color: #000000;">carry</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">])*</span><span style="color: #000000;">f</span><span style="color: #0000FF;">+</span><span style="color: #000000;">carry</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">j</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">l</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">d999</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">rfs</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">d999</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">+=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span><span style="color: #0000FF;">?</span><span style="color: #000000;">3</span><span style="color: #0000FF;">:</span><span style="color: #000000;">zc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">d999</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">carry</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">carry</span><span style="color: #0000FF;">/</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">j</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">rfs</span><span style="color: #0000FF;">[</span><span style="color: #000000;">trail</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span> <span style="color: #000000;">trail</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000080;font-style:italic;">-- d999 := quick correction for length and zeroes:</span>
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">rfs</span><span style="color: #0000FF;">[$]</span>
<span style="color: #000000;">d999</span> <span style="color: #0000FF;">=</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;"><</span><span style="color: #000000;">100</span><span style="color: #0000FF;">?</span><span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d999</span><span style="color: #0000FF;"><</span><span style="color: #000000;">10</span><span style="color: #0000FF;">?</span><span style="color: #000000;">2</span><span style="color: #0000FF;">:</span><span style="color: #000000;">1</span><span style="color: #0000FF;">):</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">-=</span> <span style="color: #000000;">d999</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rfs</span><span style="color: #0000FF;">)*</span><span style="color: #000000;">3</span><span style="color: #0000FF;">-</span><span style="color: #000000;">d999</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zeroes</span><span style="color: #0000FF;">/</span><span style="color: #000000;">digits</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">ratio</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">f</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ratio</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0.16</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Mean proportion of zero digits in factorials to %d is %.10f (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ratio</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The mean proportion dips permanently below 0.16 at %d. (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">first</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</lang>-->
{{out}}
<pre>
Mean proportion of zero digits in factorials to 100 is 0.2467531862 (0s)
Mean proportion of zero digits in factorials to 1000 is 0.2035445511 (0.2s)
Mean proportion of zero digits in factorials to 10000 is 0.1730038482 (2.3s)
The mean proportion dips permanently below 0.16 at 47332. (1 minute and 2s)
</pre>
=== trailing zeroes only ===
Should you only be interested in the ratio of trailing zeroes, you can do that much faster:
<!--<lang Phix>(phixonline)-->
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">(),</span>
<span style="color: #000000;">f10</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">log10</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">f</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">50000</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">f10</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">log10</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">digits</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">ceil</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f10</span><span style="color: #0000FF;">),</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">5</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">v</span><span style="color: #0000FF;"><=</span><span style="color: #000000;">f</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">zeroes</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">/</span><span style="color: #000000;">v</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">v</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">5</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">total</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">zeroes</span><span style="color: #0000FF;">/</span><span style="color: #000000;">digits</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">ratio</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">total</span><span style="color: #0000FF;">/</span><span style="color: #000000;">f</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ratio</span><span style="color: #0000FF;">>=</span><span style="color: #000000;">0.07</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">first</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">first</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">f</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">,</span><span style="color: #000000;">10000</span><span style="color: #0000FF;">})</span> <span style="color: #008080;">then</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Mean proportion of trailing zeroes in factorials to %d is %f\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">f</span><span style="color: #0000FF;">,</span><span style="color: #000000;">ratio</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">e</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The mean proportion dips permanently below 0.07 at %d. (%s)\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">first</span><span style="color: #0000FF;">,</span><span style="color: #000000;">e</span><span style="color: #0000FF;">})</span>
<!--</lang>-->
{{out}}
<pre>
Mean proportion of trailing zeroes in factorials to 100 is 0.170338
Mean proportion of trailing zeroes in factorials to 1000 is 0.116334
Mean proportion of trailing zeroes in factorials to 10000 is 0.081267
The mean proportion dips permanently below 0.07 at 31549. (0.1s)
</pre>


=={{header|Python}}==
=={{header|Python}}==

Revision as of 20:30, 13 June 2021

Distribution of 0 digits in factorial series is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Large Factorials and the Distribution of '0' in base 10 digits.

About the task

We can see that some features of factorial numbers (the series of numbers 1!, 2!, 3!, ...) come about because such numbers are the product of a series of counting numbers, and so those products have predictable factors. For example, all factorials above 1! are even numbers, since they have 2 as a factor. Similarly, all factorials from 5! up end in a 0, because they have 5 and 2 as factors, and thus have 10 as a factor. In fact, the factorial integers add another 0 at the end of the factorial for every step of 5 upward: 5! = 120, 10! = 3628800, 15! = 1307674368000, 16! = 20922789888000 and so on.

Because factorial numbers, which quickly become quite large, continue to have another terminal 0 on the right hand side of the number for every factor of 5 added to the factorial product, one might think that the proportion of zeros in a base 10 factorial number might be close to 1/5. However, though the factorial products add another terminating 0 every factor of 5 multiplied into the product, as the numbers become quite large, the number of digits in the factorial product expands exponentially, and so the number above the terminating zeros tends toward 10% of each digit from 0 to 1 as the factorial becomes larger. Thus, as the factorials become larger, the proportion of 0 digits in the factorial products shifts slowly from around 1/5 toward 1/10, since the number of terminating zeros in n! increases only in proportion to n, whereas the number of digits of n! in base 10 increases exponentially.

The task

Create a function to calculate the mean of the proportions of 0 digits out of the total digits found in each factorial product from 1! to N!. This proportion of 0 digits in base 10 should be calculated using the number as printed as a base 10 integer.

Example: for 1 to 6 we have 1!, 2!, 3!, 4!, 5!, 6!, or (1, 2, 6, 24, 120, 720), so we need the mean of (0/1, 0/1, 0/1, 0/2, 1/3, 1/3) = (2/3) (totals of each proportion) / 6 (= N), or 0.1111111...

Example: for 1 to 25 the mean of the proportions of 0 digits in the factorial products series of N! with N from 1 to 25 is 0.26787.

Do this task for 1 to N where N is in (100, 1000, and 10000), so, compute the mean of the proportion of 0 digits for each product in the series of each of the factorials from 1 to 100, 1 to 1000, and 1 to 10000.

Stretch task

Find the N in 10000 < N < 50000 where the mean of the proportions of 0 digits in the factorial products from 1 to N permanently falls below 0.16. This task took many hours in the Python example, though I wonder if there is a faster algorithm out there.

Go

Library: Go-rcu

Brute force as I'll be surprised if there is a faster 'exact' algorithm for this task.

However, the combination of a native code compiler and GMP really cuts down the times (2.8 seconds for the basic task and 182.5 seconds for the stretch goal). Expect these times to be reduced further by the fastest languages. <lang go>package main

import (

   "fmt"
   big "github.com/ncw/gmp"
   "rcu"

)

func main() {

   fact  := big.NewInt(1)
   sum   := 0.0
   first := int64(0)
   firstRatio := 0.0    
   fmt.Println("The mean proportion of zero digits in factorials up to the following are:")
   for n := int64(1); n <= 50000; n++  {
       fact.Mul(fact, big.NewInt(n))
       bytes  := []byte(fact.String())
       digits := len(bytes)
       zeros  := 0
       for _, b := range bytes {
           if b == '0' {
               zeros++
           }
       }
       sum += float64(zeros)/float64(digits)
       ratio := sum / float64(n)
       if n == 100 || n == 1000 || n == 10000 {
           fmt.Printf("%6s = %12.10f\n", rcu.Commatize(int(n)), ratio)
       } 
       if first > 0 && ratio >= 0.16 {
           first = 0
           firstRatio = 0.0
       } else if first == 0 && ratio < 0.16 {
           first = n
           firstRatio = ratio           
       }
   }
   fmt.Printf("%6s = %12.10f", rcu.Commatize(int(first)), firstRatio)
   fmt.Println(" (stays below 0.16 after this)")
   fmt.Println(sum/ 50000)

}</lang>

Output:
The mean proportion of zero digits in factorials up to the following are:
   100 = 0.2467531862
 1,000 = 0.2035445511
10,000 = 0.1730038482
47,332 = 0.1599999958 (stays below 0.16 after this)

Julia

<lang julia>function meanfactorialdigits(N, goal = 0.0)

   factoril, proportionsum = big"1", 0.0
   for i in 1:N
       factoril *= i
       d = digits(factoril)
       zero_proportion_in_fac = count(x -> x == 0, d) / length(d)
       proportionsum += zero_proportion_in_fac
       propmean = proportionsum / i
       if i > 15 && propmean <= goal
           println("The mean proportion dips permanently below $goal at $i.")
           break
       end
       if i == N
           println("Mean proportion of zero digits in factorials to $N is ", propmean)
       end
   end

end

@time foreach(meanfactorialdigits, [100, 1000, 10000])

@time meanfactorialdigits(50000, 0.16)

</lang>

Output:
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707
  3.030182 seconds (297.84 k allocations: 1.669 GiB, 0.83% gc time, 0.28% compilation time)
The mean proportion dips permanently below 0.16 at 47332.
179.157788 seconds (3.65 M allocations: 59.696 GiB, 1.11% gc time)

Nim

Task

Library: bignum

<lang Nim>import strutils, std/monotimes import bignum

let t0 = getMonoTime() var sum = 0.0 var f = newInt(1) var lim = 100 for n in 1..10_000:

 f *= n
 let str = $f
 sum += str.count('0') / str.len
 if n == lim:
   echo n, ":\t", sum / float(n)
   lim *= 10

echo() echo getMonoTime() - t0</lang>

Output:
100:    0.2467531861674322
1000:   0.2035445511031646
10000:  0.1730038482418671

(seconds: 2, nanosecond: 857794404)

Stretch task

Library: bignum

At each step, we eliminate the trailing zeroes to reduce the length of the number and save some time. But this is not much, about 8%.

<lang Nim>import strutils, std/monotimes import bignum

let t0 = getMonoTime() var sum = 0.0 var first = 0 var f = newInt(1) var count0 = 0 for n in 1..<50_000:

 f *= n
 while f mod 10 == 0:    # Reduce the length of "f".
   f = f div 10
   inc count0
 let str = $f
 sum += (str.count('0') + count0) / (str.len + count0)
 if sum / float(n) < 0.16:
   if first == 0: first = n
 else:
   first = 0

echo "Permanently below 0.16 at n = ", first echo "Execution time: ", getMonoTime() - t0</lang>

Output:
Permanently below 0.16 at n = 47332
Execution time: (seconds: 190, nanosecond: 215845101)

Pascal

Doing the calculation in Base 1,000,000,000 like in Primorial_numbers#alternative.
The most time consuming is converting to string and search for zeros.
Therefor I do not convert to string.I divide the base in sections of 3 digits with counting zeros in a lookup table. <lang pascal>program Factorial; {$IFDEF FPC} {$MODE DELPHI} {$Optimization ON,ALL} {$ENDIF} uses

 sysutils;

type

 tMul = array of LongWord;
 tpMul = pLongWord;

const

 LongWordDec = 1000*1000*1000;
 LIMIT = 50000;

var

 CountOfZero : array[0..999] of byte;
 SumOfRatio :array[0..LIMIT] of extended;


procedure OutMul(pMul:tpMul;Lmt :NativeInt); // for testing Begin

 write(pMul[lmt]);
 For lmt := lmt-1  downto 0 do
   write(Format('%.9d',[pMul[lmt]]));
 writeln;

end;

procedure InitCoZ; //Init Lookup table for 3 digits var

 x,y : integer;

begin

 fillchar(CountOfZero,SizeOf(CountOfZero),#0);
 CountOfZero[0] := 3; //000
 For x := 1 to 9 do
 Begin
   CountOfZero[x] := 2;     //00x
   CountOfZero[10*x] := 2;  //0x0
   CountOfZero[100*x] := 2; //x00
   y := 10;
   repeat
     CountOfZero[y+x] := 1;      //0yx
     CountOfZero[10*y+x] := 1;   //y0x
     CountOfZero[10*(y+x)] := 1; //yx0
     inc(y,10)
   until y > 100;
 end;

end;

function getFactorialDecDigits(n:NativeInt):NativeInt; var

 res: extended;

Begin

 result := -1;
 IF (n > 0) AND (n <= 1000*1000) then
 Begin
   res := 0;
   repeat res := res+ln(n); dec(n); until n < 2;
   result := trunc(res/ln(10))+1;
 end;

end;

function CntZero(pMul:tpMul;Lmt :NativeInt):NativeUint; //count zeros in Base 1,000,000,000 number var

 q,r : LongWord;
 i : NativeInt;

begin

 result := 0;
 For i := Lmt-1 downto 0 do
 Begin
   q := pMul[i];
   r := q DIV 1000;
   result +=CountOfZero[q-1000*r];//q-1000*r == q mod 1000
   q := r;
   r := q DIV 1000;
   result +=CountOfZero[q-1000*r];
   q := r;
   r := q DIV 1000;
   result +=CountOfZero[q-1000*r];
 end;

//special case first digits no leading '0'

 q := pMul[lmt];
 while q >= 1000 do
 begin
   r := q DIV 1000;
   result +=CountOfZero[q-1000*r];
   q := r;
 end;
 while q > 0 do
 begin
   r := q DIV 10;
   result += Ord( q-10*r= 0);
   q := r;
 end;

end;

function GetCoD(pMul:tpMul;Lmt :NativeInt):NativeUint; //count of decimal digits var

 i : longWord;

begin

 result := 9*Lmt;
 i := pMul[Lmt];
 while i > 1000 do
 begin
   i := i DIV 1000;
   inc(result,3);
 end;
 while i > 0 do
 begin
   i := i DIV 10;
   inc(result);
 end;

end;

procedure DoChecks(pMul:tpMul;Lmt,i :NativeInt); //(extended(1.0)* makes TIO.RUN faster // only using FPU? Begin

 SumOfRatio[i] := SumOfRatio[i-1] + (extended(1.0)*CntZero(pMul,Lmt))/GetCoD(pMul,Lmt);

end;

function MulByI(pMul:tpMul;UL,i :NativeInt):NativeInt; var

 prod  : Uint64;
 j     : nativeInt;
 carry : LongWord;

begin

 result := UL;
 carry := 0;
 For j := 0 to result do
 Begin
   prod  := i*pMul[0]+Carry;
   Carry := prod Div LongWordDec;
   pMul[0] := Prod - LongWordDec*Carry;
   inc(pMul);
 end;
 IF Carry <> 0 then
 Begin
   inc(result);
   pMul[0]:= Carry;
 End;

end;

procedure getFactorialExact(n:NativeInt); var

 MulArr : tMul;
 pMul : tpMul;
 i,ul : NativeInt;

begin

 i := getFactorialDecDigits(n) DIV 9 +10;
 Setlength(MulArr,i);
 pMul := @MulArr[0];
 Ul := 0;
 pMul[Ul]:= 1;
 i := 1;
 repeat
   UL := MulByI(pMul,UL,i);
   //Now do what you like to do with i!
   DoChecks(pMul,UL,i);
   inc(i);
 until i> n;

end;

procedure Out_(i: integer); begin

 if i > LIMIT then
   EXIT;
 writeln(i:8,SumOfRatio[i]/i:18:15);

end;

var

 i : integer;

Begin

 InitCoZ;
 SumOfRatio[0]:= 0;
 getFactorialExact(LIMIT);
 Out_(100);
 Out_(1000);
 Out_(10000);
 Out_(50000);
 i := limit;
 while i >0 do
 Begin
   if SumOfRatio[i]/i >0.16 then
     break;
   dec(i);
 end;
 inc(i);
 writeln('First ratio < 0.16 ', i:8,SumOfRatio[i]/i:20:17);

end.</lang>

Output:
     100 0.246753186167432
    1000 0.203544551103165
   10000 0.173003848241866
   50000 0.159620054602269
First ratio < 0.16    47332 0.15999999579985665 
Real time: 4.898 s  CPU share: 99.55 % // 2.67s on 2200G freepascal 3.2.2

Phix

Using "string math" to create reversed factorials, for slightly easier skipping of "trailing" zeroes, but converted to base 1000 and with the zero counting idea from Pascal, which sped it up threefold.

with javascript_semantics
sequence rfs = {1}  -- reverse factorial(1) in base 1000
         
function init_zc()
    sequence zc = repeat(0,999)
    for x=1 to 9 do
        zc[x] = 2       -- 00x
        zc[10*x] = 2    -- 0x0
        zc[100*x] = 2   -- x00
        for y=10 to 90 by 10 do
            zc[y+x] = 1         -- 0yx
            zc[10*y+x] = 1      -- y0x
            zc[10*(y+x)] = 1    -- yx0
        end for
    end for
    return zc
end function
constant zc = init_zc()

atom t0 = time(),
     total = 0
integer trail = 1,
        first = 0
for f=2 to iff(platform()=JS?10000:50000) do
    integer carry = 0, d999, 
            zeroes = (trail-1)*3, 
            j = trail, l = length(rfs)
    while j<=l or carry do
        if j<=l then
            carry = (rfs[j])*f+carry
        end if
        d999 = remainder(carry,1000)
        if j<=l then
            rfs[j] = d999
        else
            rfs &= d999
        end if
        zeroes += iff(d999=0?3:zc[d999])
        carry = floor(carry/1000)
        j += 1
    end while
    while rfs[trail]=0 do trail += 1 end while
    -- d999 := quick correction for length and zeroes:
    d999 = rfs[$]
    d999 = iff(d999<100?iff(d999<10?2:1):0)
    zeroes -= d999
    integer digits = length(rfs)*3-d999

    total += zeroes/digits
    atom ratio = total/f
    if ratio>=0.16 then
        first = 0
    elsif first=0 then
        first = f
    end if
    if find(f,{100,1000,10000}) then
        string e = elapsed(time()-t0)
        printf(1,"Mean proportion of zero digits in factorials to %d is %.10f (%s)\n",{f,ratio,e})
    end if
end for
if platform()!=JS then
    string e = elapsed(time()-t0)
    printf(1,"The mean proportion dips permanently below 0.16 at %d. (%s)\n",{first,e})
end if
Output:
Mean proportion of zero digits in factorials to 100 is 0.2467531862 (0s)
Mean proportion of zero digits in factorials to 1000 is 0.2035445511 (0.2s)
Mean proportion of zero digits in factorials to 10000 is 0.1730038482 (2.3s)
The mean proportion dips permanently below 0.16 at 47332. (1 minute and 2s)

trailing zeroes only

Should you only be interested in the ratio of trailing zeroes, you can do that much faster:

with javascript_semantics
atom t0 = time(),
     f10 = log10(1),
     total = 0
integer first = 0
for f=2 to 50000 do
    f10 += log10(f)
    integer digits = ceil(f10),
            zeroes = 0,
            v = 5
    while v<=f do
        zeroes += floor(f/v)
        v *= 5
    end while
    total += zeroes/digits
    atom ratio = total/f
    if ratio>=0.07 then
        first = 0
    elsif first=0 then
        first = f
    end if
    if find(f,{100,1000,10000}) then
        printf(1,"Mean proportion of trailing zeroes in factorials to %d is %f\n",{f,ratio})
    end if
end for
string e = elapsed(time()-t0)
printf(1,"The mean proportion dips permanently below 0.07 at %d. (%s)\n",{first,e})
Output:
Mean proportion of trailing zeroes in factorials to 100 is 0.170338
Mean proportion of trailing zeroes in factorials to 1000 is 0.116334
Mean proportion of trailing zeroes in factorials to 10000 is 0.081267
The mean proportion dips permanently below 0.07 at 31549. (0.1s)

Python

<lang python>def facpropzeros(N, verbose = True):

   proportions = [0.0] * N
   fac, psum = 1, 0.0
   for i in range(N):
       fac *= i + 1
       d = list(str(fac))
       psum += sum(map(lambda x: x == '0', d)) / len(d)
       proportions[i] = psum / (i + 1)
   if verbose:
       print("The mean proportion of 0 in factorials from 1 to {} is {}.".format(N, psum / N))
   return proportions


for n in [100, 1000, 10000]:

   facpropzeros(n)

props = facpropzeros(47500, False) n = (next(i for i in reversed(range(len(props))) if props[i] > 0.16))

print("The mean proportion dips permanently below 0.16 at {}.".format(n + 2))

</lang>

Output:
The mean proportion of 0 in factorials from 1 to 100 is 0.24675318616743216.
The mean proportion of 0 in factorials from 1 to 1000 is 0.20354455110316458.
The mean proportion of 0 in factorials from 1 to 10000 is 0.17300384824186707.
The mean proportion dips permanently below 0.16 at 47332.

The means can be plotted, showing a jump from 0 to over 0.25, followed by a slowly dropping curve: <lang python>import matplotlib.pyplot as plt plt.plot([i+1 for i in range(len(props))], props) </lang>

Raku

Works, but depressingly slow for 10000.

<lang perl6>sub postfix:<!> (Int $n) { ( constant factorial = 1, 1, |[\*] 2..* )[$n] } sink 10000!; # prime the iterator to allow multithreading

sub zs ($n) { ( constant zero-share = (^Inf).race(:32batch).map: { (.!.comb.Bag){'0'} / .!.chars } )[$n] }

.say for (

    100
   ,1000
   ,10000

).map: -> \n { "{n}: {([+] (^n).map: *.&zs) / n}" }</lang>

Output:
100: 0.24485445199021696
1000: 0.20336075048011162
10000: 0.17298757510670162

REXX

<lang rexx>/*REXX program computes the mean of the proportion of "0" digits a series of factorials.*/ parse arg $ /*obtain optional arguments from the CL*/ if $= | $="," then $= 100 1000 10000 /*not specified? Then use the default.*/

  1. = words($) /*the number of ranges to be used here.*/

numeric digits 100 /*increase dec. digs, but only to 100. */ big= word($, #);  != 1 /*obtain the largest number in ranges. */

                               do i=1  for big  /*calculate biggest  !  using 100 digs.*/
                               != ! * i         /*calculate the factorial of  BIG.     */
                               end   /*i*/

if pos('E', !)>0 then do /*In exponential format? Then get EXP.*/

                      parse var !  'E'  x       /*parse the exponent from the number.  */
                      numeric digits    x+1     /*set the decimal digits to  X  plus 1.*/
                      end                       /* [↑]  the  +1  is for the dec. point.*/

title= ' mean proportion of zeros in the (decimal) factorial products for N' say ' N │'center(title, 80) /*display the title for the output. */ say '───────────┼'center("" , 80, '─') /* " a sep " " " */

 do j=1  for #;  n= word($, j)                  /*calculate some factorial ranges.     */
 say center( commas(n), 11)'│' left(0dist(n), 75)...    /*show results for above range.*/
 end   /*j*/

say '───────────┴'center("" , 80, '─') /*display a foot sep for the output. */ exit 0 /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: parse arg ?; do jc=length(?)-3 to 1 by -3; ?=insert(',', ?, jc); end; return ? /*──────────────────────────────────────────────────────────────────────────────────────*/ 0dist: procedure; parse arg z;  != 1; y= 0

                    do k=1  for z;    != ! * k;     y= y   +   countstr(0, !) / length(!)
                    end   /*k*/
       return y/z</lang>
output   when using the default inputs:
     N     │       mean proportion of zeros in the (decimal) factorial products for  N
───────────┼────────────────────────────────────────────────────────────────────────────────
    100    │ 0.2467531861674322177784158871973526991129407033266153063813195937196095976...
   1,000   │ 0.2035445511031646356400438031711455302985741167890402203486699704599684047...
  10,000   │ 0.1730038482418660531800366428930706156810278809057883361518852958446868172...
───────────┴────────────────────────────────────────────────────────────────────────────────

Wren

Library: Wren-big
Library: Wren-fmt

Very slow indeed, 10.75 minutes to reach N = 10,000. <lang ecmascript>import "/big" for BigInt import "/fmt" for Fmt

var fact = BigInt.one var sum = 0 System.print("The mean proportion of zero digits in factorials up to the following are:") for (n in 1..10000) {

   fact = fact * n
   var bytes = fact.toString.bytes
   var digits = bytes.count
   var zeros  = bytes.count { |b| b == 48 }
   sum = sum + zeros / digits
   if (n == 100 || n == 1000 || n == 10000) {
       Fmt.print("$,6d = $12.10f", n, sum / n)
   }

}</lang>

Output:
The mean proportion of zero digits in factorials up to the following are:
   100 = 0.2467531862
 1,000 = 0.2035445511
10,000 = 0.1730038482