# Binomial distribution in table

Here you can find how to calculate and print table for the binomial distribution. I would like to get rid of those lines that are all empty due to too small probabilities (<=0.0000).

I used the answer given to the above mentioned question (see here). Then I added a new \mySAVETable. With the help of the etoolbox package (as already used in the answer) I tried to save only those lines that contain at least one probabilty. I also introduced a new counter to count the number of empty cells. Fortunately, this works all fine. However, cancelling the all empty lines fails. I get an empty table instead, only the head and the foot are printed.

Here is my code:

\documentclass[]{article}
\usepackage{amsmath}
\usepackage[margin=.5cm, showframe=true]{geometry}
\usepackage{booktabs}
\usepackage{pgf,pgffor}
\usepackage{etoolbox}
\usepgflibrary{fpu}
\pgfkeys{/pgf/fpu}
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}
\pgfkeys{/pgf/number format/.cd,fixed,fixed zerofill,precision=4}

%%% Defining basic stuff
\def\myHeadList{0.05, 0.10, 1/6, 0.20, 0.25, 0.30, 1/3, 0.40, 0.45, 0.50}
\def\myFootList{0.95, 0.90, 5/6, 0.80, 0.75, 0.70, 2/3, 0.60, 0.55, 0.50}
\newcounter{EmptyCells}
\setcounter{EmptyCells}{0}
%\def\startN{9}
%\def\endN{10}

\newif\ifsomanyzeroesshouldbeprinted
\newcommand*{\binomTable}[3][0]{% #1  = 0 => results in the form 0.0000 are typeset
% #1 != 0 => results in the form 0.0000 are omitted
% #2 = startN
% #3 = endN
\edef\startN{#2}%
\edef\endN{#3}%
\expandafter\ifnum#1=0\relax%
\somanyzeroesshouldbeprintedtrue%
\else%
\somanyzeroesshouldbeprintedfalse%
\fi%
%
\def\myHead{ $n$ & $k$}%
\xappto\myHead{& {$\p$}}%
}%
\appto\myHead{& $k$ & EmptyCells\\}%
%
%%% Building foot of table
\def\myFoot{ $n$ & $k$}%
\foreach \p in \myFootList {%
\xappto\myFoot{& {$\p$}}%
}%
\appto\myFoot{& $k$ & EmptyCells\\}%
%
%%% Bulding body of table
\def\myTable{}%
\def\mySAVETable{}%
\def\myN{\startN,...,\endN}%
\foreach \n in \myN {%
\foreach \k in {0,...,\n}{%
\setcounter{EmptyCells}{0}
\ifnum\k=0\relax%
\xappto\myTable{\noexpand\midrule\n}%
\fi%
\xappto\myTable{& \k}%
\pgfmathsetmacro{\binomProduct}{1}%
\xdef\myTempValue{\binomProduct}%
\ifnum\k=0\relax%
\xdef\oldK{\k}%
\else%
\foreach \j in {1,...,\k}{%
\pgfmathsetmacro{\binomProduct}{\myTempValue*(\n+1-\j)/\j}%
\xdef\myTempValue{\binomProduct}%
}%
\fi%
\pgfmathsetmacro{\myTempValue}{round(\myTempValue)}%
%            \xappto\myTable{& \noexpand\pgfmathprintnumber[/pgf/number format/.cd,fixed,precision=0,set thousands separator={\,},min exponent for 1000 sep=4]{\myTempValue}}%
\pgfmathsetmacro{\result}{\myTempValue*\p^(\k)*(1-\p)^(\n-\k)}%
\ifsomanyzeroesshouldbeprinted%
\xappto\myTable{& \noexpand\pgfmathprintnumber[skip 0.=true, dec sep={}]{\result}}%
\else%
\ifdim\result pt<0.00005pt\relax%
\gappto\myTable{&}%
\else%
\xappto\myTable{& \noexpand\pgfmathprintnumber[skip 0.=true, dec sep={}]{\result}}%
\fi%
\fi%
}%
\pgfmathsetmacro{\result}{\n-\k}%
\xappto\myTable{& \noexpand\pgfmathprintnumber[/pgf/number format/.cd,fixed,precision=0,set thousands separator={\,},min exponent for 1000 sep=4]{\result} & \arabic{EmptyCells}}%
\gappto\myTable{\\}%
\ifnum\arabic{EmptyCells}=10%
\else%
\appto\mySAVETable{\myTable}%
\fi%
}%
}%
}
\pagestyle{empty}

\begin{document}
\binomTable[1]{15}{17}
\begin{tabular}{rrr*{10}{r}r}
\end{tabular}
\end{document}

• Does the solution have to employ the pgf package, or might you be interested in an alternative, LuaLaTeX-based solution? Please advise.
– Mico
Jul 22 '19 at 8:37
• Thanks for your suggestion. I would rather like to have a pdfLaTeX solution. I guess LuaLaTeX would be faster in calculating. But I'm still using pdfLaTeX only. Sorry. Jul 22 '19 at 12:19

Here's a LuaLaTeX-based solution. The OP has indicated that he/she would a pdfLaTeX-based solution; unfortunately, I don't know how to create such a solution. :-( Hopefully, my answer will be useful to other readers in the future.

The binomial probabilities are computed for various values of n, k(0\le k\le n), and 10 probabilities pevenly spaced between 0.05 and 0.50. The main Lua function shown below performs its work with three nested for loops: n ranges from 2 to n_max, k ranges from 0 to n, and p ranges from 0.05 to 0.50. The binomial probabilities are rounded to 4 digits after the decimal marker. To address your main formatting request, they are displayed as 0 if their values are less than 0.5e-4. (Speaking for myself, I find it easier to navigate a table with lots of 0 cells rather than one with lots of entirely blank cells.) In addition, if a probability can be displayed using fewer than 4 digits, the program leaves off the trailing zeros. E.g., for n=2 and p=0.1, the probabilities are shown as 0.81, 0.18, and 0.01 for k=0,1,2 in the first screenshot shown below. Similarly, for n=2 and p=0.5, the probabilities are shown as 0.25, 0.5, and 0.25 for k=0,1,2.

The code displayed below creates a longtable that stretches over roughly 2-1/2 pages. The screenshots are taken from the top and bottom of the longtable.

\documentclass{article}
\usepackage[a4paper,margin=2.3cm]{geometry} % choose suitable page parameters
\usepackage{longtable,booktabs,array}

\usepackage{luacode}
\begin{luacode}

-- utility functions to round numbers to a preset number of digits
function round2int ( x )
return x>=0 and math.floor(x+0.5) or math.ceil(x-0.5)
end
function round ( num , digits )
return round2int ( num * 10^digits ) / 10^digits
end

-- print the header row of the binomial probabilities table
for p=1,10 do
tex.sprint ( "{"..string.format("%.2f",p/20) .. "}" )
if p<10 then tex.sprint ("&") end
end
end

-- functions to compute factorials, # of permutations, and binom. probabilities
function factorial ( t )
if t==0 or t==1 then return 1
else return ( t * factorial(t-1) )
end
end

function perm ( n , k ) -- 0 \le k \le n
return ( factorial(n) / (factorial(n-k)*factorial(k) ) )
end

function prob ( n , k , p )
return ( p^k * (1-p)^(n-k) * perm(n,k) )
end

-- The main Lua function:
function create_binom_table ( nmax )
for n = 2 , nmax do
tex.sprint ( n )
for k = 0 , n do
tex.sprint ( "&" .. k .. "&" )
for p = 1,10 do
-- round result to four digits
px = round ( prob ( n, k , p/20 ) , 4 )
tex.sprint ( string.format("%.4g", px ) )
if p < 10 then tex.sprint ( "&" ) end
end
tex.sprint ( "\\\\" )
end
if n < nmax then
end
end
end

\end{luacode}

\begin{document}
\begin{longtable}{@{} rr *{10}{l} @{}}

\toprule
$n$ & $k$ & \multicolumn{10}{c@{}}{$p$}\\
\cmidrule(l){3-12}
\midrule

\midrule
\multicolumn{12}{r@{}}{\footnotesize(Continued on next page)}\\
\endfoot

\bottomrule
\endlastfoot

% call the main Lua function, with n=2 until n=15
\directlua{create_binom_table ( 15 )}

\end{longtable}
\end{document}


Addendum: I just noticed that while the OP's code is set to form a table with ten success probabilities ranging from 0.05 to 0.5, these probabilities are not evenly spaced. Adjusting the code above to handle such a case is not difficult.

• Insert the following instruction near the top of the Lua code block:

-- vector of success probabilities
pvec={0.05,0.1,1/6,0.2,0.25,0.3,1/3,0.4,0.45,0.5}

• In the function make_header_row, change the line

          tex.sprint ( "{"..string.format("%.2f",p/20) .. "}" )


to

          tex.sprint ( "{"..string.format("%.4g",pvec[p]) .. "}" )

• In the function create_binom_table, change the line

            px = round ( prob ( n, k , p/20 ) , 4 )


to

            px = round ( prob ( n, k , pvec[p] ) , 4 )


The rest of can remain unchanged.