# Division by zero and precision in math calculations

I have this table who is like almost to all my wishes:

This is my code:

\documentclass[border=5pt]{standalone}
\usepackage{tikz,siunitx,calc}

\begin{document}

\sisetup{round-mode = places, round-precision = 3}

\begin{tikzpicture}
\fill[fill=gray!40] (-.5,31.3) rectangle (6.0,31.9);
\fill[fill=gray!40] (-.5,12.7) rectangle (.4,31.9);
\fill[fill=red!20] (5.2,12.7) rectangle (6,31.3);
%\draw[line width=1.5] (-.3,31.7)--(6.0,31.7);
%\draw[line width=1.5] (-.3,12.2)--(6.0,12.2);
\draw[line width=2pt,latex-latex] (.4,12.7)--(.4,31.3)--(5.2,31.3);

\draw (0,31.6) node {\bfseries $x$}
(1,31.6) node[cyan] {\bfseries $\sin x$}
(2.2,31.6) node[magenta] {\bfseries $\cos x$}
(3.4,31.6) node[blue] {\bfseries $\tan x$}
(4.6,31.6) node[violet] {\bfseries $\cot x$};
\foreach \i in {0,...,45}{
\pgfmathsetmacro{\j}{int(90-\i)}
\pgfmathsetmacro{\s}{sin(\i)}
\pgfmathsetmacro{\c}{cos(\i)}
\pgfmathsetmacro{\t}{tan(\i)}
\pgfmathsetmacro{\ct}{cot(\i)}
\draw (0,31-.4*\i) node {\bfseries \i}
(1,31-.4*\i) node[cyan] {\num{\s}}
(2.2,31-.4*\i) node[magenta] {\num{\c}}
(3.4,31-.4*\i) node[blue] {\num{\t}}

(4.6,31-.4*\i) node[violet] {\num{\ct}}
(5.6,31-.4*\i) node[red] {\bfseries \j};
}

\draw (4.6,31) node[fill=white] {\;\;$\infty$};

\fill[fill=red!20] (-.5,12.2) rectangle (6.0,12.8);
\draw[red,line width=2pt,latex-latex] (5.2,31.2)--(5.2,12.8)--(.5,12.8);
%\draw[line width=1.5] (6.0,12.2)--(6.0,31.7);
%\draw[line width=1.5] (-.3,12.2)--(-.3,31.7);
\draw (1,12.4) node[cyan] {\bfseries $\cos x$}
(2.2,12.4) node[magenta] {\bfseries $\sin x$}
(3.4,12.4) node[blue] {\bfseries $\cot x$}
(4.6,12.4) node[violet] {\bfseries $\tan x$}
(5.6,12.4) node[red] {\bfseries $x$};
\end{tikzpicture}
\end{document}


I say almost because:

1. The compilation is complete but whit errors:
2. If I fix the precision to 4 decimal digits I have tan(45)=cot(45)=1.0001 that is incorrect.

Can someone help me to avoid this errors?

• avoid calculating cot(0) for the error, for the accuracy tex is using fixed point \dimen arithmetic, I doubt any of the values are accurate to 4dp Oct 14, 2022 at 9:45
• @DavidCarlisle I dont know how to avoid the calculus of cot(0). I know this is the problem, but how avoid it? For the precision they are some package that have better precision in this case? Oct 14, 2022 at 9:49
• I do love to create tables with TeX myself, however, no one is going to blame you for creating the values somewhere else (even if it's Excel) and only typeset it with TikZ. Of course, with LuaLaTeX, we can use Lua to calculate values (though, I don't know how precise they are). Oct 14, 2022 at 20:36

It's a strange way of making a table (with explicit coordinates etc, maybe you should have a look at matrix of nodes in TikZ). I did the following:

1. use the xfp floating point library, which is much more precise than pgfmath (notice that sin in xfp defaults to radians, so I used the sind variant here);
2. use the xifthen library to add the tests;
3. "enlarged" the table with the xscale=1.2 trick to have the 4 digits fit.
\documentclass[border=5pt]{standalone}
\usepackage{tikz,siunitx,calc,xfp, xifthen}

\begin{document}

\sisetup{round-mode = places, round-precision = 4}

\begin{tikzpicture}[xscale=1.2]
\fill[fill=gray!40] (-.5,31.3) rectangle (6.0,31.9);
\fill[fill=gray!40] (-.5,12.7) rectangle (.4,31.9);
\fill[fill=red!20] (5.2,12.7) rectangle (6,31.3);
%\draw[line width=1.5] (-.3,31.7)--(6.0,31.7);
%\draw[line width=1.5] (-.3,12.2)--(6.0,12.2);
\draw[line width=2pt,latex-latex] (.4,12.7)--(.4,31.3)--(5.2,31.3);

\draw (0,31.6) node {\bfseries $x$}
(1,31.6) node[cyan] {\bfseries $\sin x$}
(2.2,31.6) node[magenta] {\bfseries $\cos x$}
(3.4,31.6) node[blue] {\bfseries $\tan x$}
(4.6,31.6) node[violet] {\bfseries $\cot x$};
\foreach \i in {0,...,45}{
\edef\myj{\fpeval{(90-\i)}}
\edef\mys{\fpeval{sind(\i)}}
\edef\myc{\fpeval{cosd(\i)}}
\edef\myt{\fpeval{tand(\i)}}
\ifthenelse{\i=0}{\edef\mct{-1}}{% placeholder, not used
\edef\mct{\fpeval{cotd(\i)}}}
\draw (0,31-.4*\i) node {\bfseries \i}
(1,31-.4*\i) node[cyan] {\num{\mys}}
(2.2,31-.4*\i) node[magenta] {\num{\myc}}
(3.4,31-.4*\i) node[blue] {\num{\myt}}
(5.6,31-.4*\i) node[red] {\bfseries \myj};
\ifthenelse{\i=0}{%
\draw (4.6,31-.4*\i) node[violet] {\;\;$\infty$};
}{
\draw (4.6,31-.4*\i) node[violet] {\num{\mct}};
}
}
\fill[fill=red!20] (-.5,12.2) rectangle (6.0,12.8);
\draw[red,line width=2pt,latex-latex] (5.2,31.2)--(5.2,12.8)--(.5,12.8);
%\draw[line width=1.5] (6.0,12.2)--(6.0,31.7);
%\draw[line width=1.5] (-.3,12.2)--(-.3,31.7);
\draw (1,12.4) node[cyan] {\bfseries $\cos x$}
(2.2,12.4) node[magenta] {\bfseries $\sin x$}
(3.4,12.4) node[blue] {\bfseries $\cot x$}
(4.6,12.4) node[violet] {\bfseries $\tan x$}
(5.6,12.4) node[red] {\bfseries $x$};
\end{tikzpicture}
\end{document}


• Very good! The precision of numeric calculus is well over 4dp. I tested for 7dp, but I would need to enlarge the table. My table was only one exercise for myself (I am 75 years old!). Your code to avoid division by zero is similar to my tries (not posted): I used \if and You \ifthenelse (with the good package). Thanks again. Oct 14, 2022 at 14:34
• @RaffaeleSantoro, xfp (which is really the LaTeX3 floating point engine) should have IEEE754 precision. That is much more than the pgfmath one, which is based on inner TeX dimension (32 bit, I think). On the other hand, it's slower... Oct 14, 2022 at 14:40

Replace

\pgfmathsetmacro{\ct}{cot(\i)}


with

\ifnum\i=0
\def\ct{$\infty$}
\else
\def\ct{\pgfmathparse{cot(\i)}\tablenum{\pgfmathresult}}
\fi


table-format=2.3


to your \sisetup and remove the white-out node

\draw (4.6,31) node[fill=white] {\;\;$\infty$};


which isn't necessary anymore.

Then you can use

      (4.6,31-.4*\i) node[violet]  {\ct} % ← no \num anymore


in the last \draw of the loop.

The \ifnum primitive is just a very low-level form of testing integers. You can of course use any other ifthen solution here.

The core of it is to only calculate cot(\i) when \i isn't 0, if it is, then print only \infty.

## Code

\documentclass[border=5pt]{standalone}
\usepackage{tikz,siunitx}
\begin{document}
\sisetup{round-mode = places, round-precision = 3, table-format=2.3}
\begin{tikzpicture}
\fill[fill=gray!40] (-.5,31.3) rectangle (6.0,31.9);
\fill[fill=gray!40] (-.5,12.7) rectangle (.4,31.9);
\fill[fill=red!20]  (5.2,12.7) rectangle (6,31.3);

\draw[line width=2pt,latex-latex] (.4,12.7)--(.4,31.3)--(5.2,31.3);

\draw (0,31.6) node          {\bfseries $x$}
(1,31.6) node[cyan]    {\bfseries $\sin x$}
(2.2,31.6) node[magenta] {\bfseries $\cos x$}
(3.4,31.6) node[blue]    {\bfseries $\tan x$}
(4.6,31.6) node[violet]  {\bfseries $\cot x$};
\foreach \i in {0,...,45}{
\pgfmathsetmacro{\j}{int(90-\i)}
\pgfmathsetmacro{\s}{sin(\i)}
\pgfmathsetmacro{\c}{cos(\i)}
\pgfmathsetmacro{\t}{tan(\i)}
\ifnum\i=0
\def\ct{$\infty$}
\else
\def\ct{\pgfmathparse{cot(\i)}\tablenum{\pgfmathresult}}
\fi

\draw (0,  31-.4*\i) node          {\bfseries \i}
(1,  31-.4*\i) node[cyan]    {\num{\s}}
(2.2,31-.4*\i) node[magenta] {\num{\c}}
(3.4,31-.4*\i) node[blue]    {\num{\t}}
(4.6,31-.4*\i) node[violet]  {\ct} % ←
(5.6,31-.4*\i) node[red]     {\bfseries \j};
}
\fill[fill=red!20] (-.5,12.2) rectangle (6.0,12.8);
\draw[red, line width=2pt, latex-latex] (5.2,31.2)--(5.2,12.8)--(.5,12.8);

\draw (1  ,12.4) node[cyan]    {\bfseries $\cos x$}
(2.2,12.4) node[magenta] {\bfseries $\sin x$}
(3.4,12.4) node[blue]    {\bfseries $\cot x$}
(4.6,12.4) node[violet]  {\bfseries $\tan x$}
(5.6,12.4) node[red]     {\bfseries $x$};
\end{tikzpicture}
\end{document}


## Output

• Thanks for yours contribution! But I have two errors with yours changes: Package siunitx Error: Invalid number '$\infty$'. } Incomplete \iffalse; all text was ignored after line 39. Oct 14, 2022 at 14:18
• @RaffaeleSantoro That's on me for not posting the full code. The node needs to be adjusted as well, it's only \ct now – without \num. Oct 14, 2022 at 14:29

I want to show off a more automatic approach on making such a table.

While I still think, it won't hurt anyone using an external tool to calculate the values and just pasting them into your document, we can also let them be calculated

• by PGFmath (with bad precision),
• by the PGF library fpu (with still bad precision),
• with the L3 xfp package (see Rmano's answer) (or similar packages) or, for example,
• with Lua when using LuaLaTeX.

Either way you choose you're going to adjust the \prntFormula macro a bit.

With PGFmath or the fpu library, it's

\newcommand*\prntFormula[1]{\pgfmathparse{#1}\pgfmathprintnumber{\pgfmathresult}}


With Lua, it's

\renewcommand*\prntFormula[1]{%
\edef\pgfmathresult{\directlua{tex.print(#1)}}\pgfmathprintnumber{\pgfmathresult}}


while is what I'm using here. I have defined some shortcuts so that I can use the same function names as with PGFmath.

With the xfp package, you will need to smuggle a d in since the normal functions default to radians.

Looks like Lua supports a precision of 15 digits which is what I will be using here. Not that anyone needs that many digits …

## Code

\documentclass[border=5pt,tikz]{standalone}
\makeatletter
\newcommand*\repeatMe[2]{\ifnum#1=0 \expandafter\@gobble\else\expandafter\@firstofone\fi{#2\expandafter\repeatMe\expandafter{\the\numexpr#1-1\relax}{#2}}}
\makeatother
\newcommand*\prntFormula[1]{\pgfmathparse{#1}\pgfmathprintnumber{\pgfmathresult}}
%% Or with Lua:
\pgfkeys{/make lua shortcut/.code args={#1=#2}{\directlua{#1 = function (x) return #2(math.rad(x)) end}},
/make lua shortcut/.list={sin=math.sin, cos=math.cos, tan=math.tan, cot=1/math.tan}}
\renewcommand*\prntFormula[1]{\edef\pgfmathresult{\directlua{tex.print(#1)}}\pgfmathprintnumber{\pgfmathresult}}
%%
\usetikzlibrary{arrows.meta,matrix}
\begin{document}
\begin{tikzpicture}[
arrows={[scale=.6667]},
tight matrix/.style={every outer matrix/.append style={inner sep=+0pt}},
precision/.style args={#1.#2}{number format={precision={#2}}, text width=width("\repeatMe{#1}{0}\ifnum#2>0 .\fi\repeatMe{#2}{0}")},
nc/.code=\def\nc{#1}, % "node contents"
columns/.style 2 args={/utils/tempa/.style={column ##1/.append style={#2}},/utils/tempa/.list={#1}},
rows/.style 2 args   ={/utils/tempa/.style={row ##1/.append style={#2}},   /utils/tempa/.list={#1}},
range lists/.style args={rows#1columns#2=#3}{/utils/tempa/.style={/utils/tempb/.style={row ##1 column ####1/.append style={#3}},/utils/tempb/.list={#2}},/utils/tempa/.list={#1}},
/pgf/number format/.code=\pgfqkeys{/pgf/number format}{#1}]
\newcommand*\nc{}% default value
\newcommand*\currentx{\the\numexpr\the\pgfmatrixcurrentrow-2\relax}
\newcommand*\reversex{\the\numexpr90-\currentx\relax}
\matrix[
ampersand replacement=\&, matrix of math nodes, tight matrix, inner xsep=\tabcolsep,
number format={fixed, fixed zerofill=true},
cells       = {align=right, precision=1.3, text height=height("0")},
columns     = {1,6}  {text width=width("00")},
columns     = {2}    {cyan,    nc=\prntFormula{sin(\currentx)}, precision=1.14},
columns     = {3}    {magenta, nc=\prntFormula{cos(\currentx)}, precision=1.14},
columns     = {4}    {blue,    nc=\prntFormula{tan(\currentx)}, precision=1.14},
columns     = {5}    {violet,  nc=\prntFormula{cot(\currentx)}, precision=2.13},
rows        = {1}    {align=center, nodes={fill=gray!40}},
rows        = {48}   {align=center, nodes={fill=red!20}},
range lists = {rows 2,...,47 columns 1 = nc=\currentx, nodes={fill=gray!40}},
range lists = {rows 2,...,47 columns 6 = nc=\reversex, nodes={fill=red!20}},
range lists = {rows 2        columns 5 = nc=\infty, align=center},
range lists = {rows 3,...,7  columns 5 = precision=2.12, execute at end node=\hphantom{0}}
] (m) {
x \& \sin x \& \cos x \& \tan x \& \cot x \& {}          \\
\repeatMe{46}{||\currentx \& ||\nc  \& ||\nc  \& ||\nc  \& ||\nc  \& ||\reversex \\}
{} \& \cos x \& \sin x \& \cot x \& \tan x \& x           \\ };
\draw[line width=2pt, Latex-Latex] (m-47-2.south west) |- (m-2-5.north east);
\draw[line width=2pt, Latex-Latex] (m-47-2.south west) -| (m-2-5.north east) [red];
\end{tikzpicture}
\end{document}