Distribution of 0 digits in factorial series: Difference between revisions

Line 194:
<pre>
Same as 'brute force' version.
</pre>
 
=={{header|jq}}==
'''Works with jq'''
 
The precision of jq's integer arithmetic is not up to this task, so in the following we borrow from the "BigInt" library and use a string representation of integers.
 
Unfortunately, although gojq (the Go implementation of jq) does support unbounded-precision integer arithmetic, it is unsuited for the task because of memory management issues.
 
'''From BigInt.jq'''
<lang jq>
# multiply two decimal strings, which may be signed (+ or -)
def long_multiply(num1; num2):
 
def stripsign:
.[0:1] as $a
| if $a == "-" then [ -1, .[1:]]
elif $a == "+" then [ 1, .[1:]]
else [1, .]
end;
 
def adjustsign(sign):
if sign == 1 then . else "-" + . end;
 
# mult/2 assumes neither argument has a sign
def mult(num1;num2):
(num1 | explode | map(.-48) | reverse) as $a1
| (num2 | explode | map(.-48) | reverse) as $a2
| reduce range(0; num1|length) as $i1
([]; # result
reduce range(0; num2|length) as $i2
(.;
($i1 + $i2) as $ix
| ( $a1[$i1] * $a2[$i2] + (if $ix >= length then 0 else .[$ix] end) ) as $r
| if $r > 9 # carrying
then
.[$ix + 1] = ($r / 10 | floor) + (if $ix + 1 >= length then 0 else .[$ix + 1] end )
| .[$ix] = $r - ( $r / 10 | floor ) * 10
else
.[$ix] = $r
end
)
)
| reverse | map(.+48) | implode;
 
(num1|stripsign) as $a1
| (num2|stripsign) as $a2
| if $a1[1] == "0" or $a2[1] == "0" then "0"
elif $a1[1] == "1" then $a2[1]|adjustsign( $a1[0] * $a2[0] )
elif $a2[1] == "1" then $a1[1]|adjustsign( $a1[0] * $a2[0] )
else mult($a1[1]; $a2[1]) | adjustsign( $a1[0] * $a2[0] )
end;
</lang>
'''The task'''
<lang jq>
def count(s): reduce s as $x (0; .+1);
 
def meanfactorialdigits:
def digits: tostring | explode;
def nzeros: count( .[] | select(. == 48) ); # "0" is 48
. as $N
| 0.16 as $goal
| label $out
| reduce range( 1; 1+$N ) as $i ( {factorial: "1", proportionsum: 0.0, first: null };
.factorial = long_multiply(.factorial; $i|tostring)
| (.factorial|digits) as $d
| .proportionsum += ($d | (nzeros / length))
| (.proportionsum / $i) as $propmean
| if .first
then if $propmean > $goal then .first = null else . end
elif $propmean <= $goal then .first = $i
else .
end)
| "Mean proportion of zero digits in factorials to \($N) is \(.proportionsum/$N);" +
(if .first then " mean <= \($goal) from N=\(.first) on." else " goal (\($goal)) unmet." end);
 
# The task:
100, 1000, 10000 | meanfactorialdigits</lang>
{{out}}
<pre>
Mean proportion of zero digits in factorials to 100 is 0.24675318616743216; mean <= 0.16 from N=null on.
Mean proportion of zero digits in factorials to 1000 is 0.20354455110316458; mean <= 0.16 from N=null on.
Mean proportion of zero digits in factorials to 10000 is 0.17300384824186707; mean <= 0.16 from N=null on.
</pre>
 
2,449

edits