[Tex/LaTex] simple way of improving the precision of pgfmath for trig functions

pgfmathtikz-pgf

I wanted to build a table of trig values using pgfmath. However, the precision is a bit off. Is there a way to improve this within TikZ?

This is related to a similar question I just posted: Is there a way to pad zeros to the end of a rounded number with Expl3?

Here's my current working example:

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc,fixedpointarithmetic}

\def\mynum{0}
\def\myvoffset{0pt}

\usepackage[margin=0.5in]{geometry}

\begin{document}

Using \texttt{TikZ}

\begin{tikzpicture}[/pgf/number format/.cd,fixed,precision=4,verbatim]

  \coordinate(UL) at (0,0);

  \node at (UL) {Degrees};
  \node[anchor=west] at ($(UL.west)+(1cm,0)$) {$\sin$};
  \node[anchor=west] at ($(UL.west)+(2.75cm,0)$) {$\cos$};
  \node[anchor=west] at ($(UL.west)+(4.50cm,0)$) {$\tan$};

  \foreach \myn in {1,2,3,...,45}
  {
    \pgfmathparse{int(mod(\myn-1,5))}
    \ifnum\pgfmathresult=0\relax
      \xdef\myvoffset{\dimexpr\myvoffset+1.350\baselineskip}%%
    \else
      \xdef\myvoffset{\dimexpr\myvoffset+1.00\baselineskip}%%
    \fi

    \coordinate (DEG/\myn)   at ($(UL.west)-(0,\myvoffset)$);
    \coordinate (DEG/S/\myn) at ($(DEG/\myn)+(1cm,0)$);
    \coordinate (DEG/C/\myn) at ($(DEG/S/\myn)+(1.75cm,0)$);
    \coordinate (DEG/T/\myn) at ($(DEG/C/\myn)+(1.75cm,0)$);

    \node[anchor=east] at (DEG/\myn) {$\myn^\circ$};
    \pgfmathparse{sin(\myn)} \node[anchor=west] at (DEG/S/\myn) {\texttt{\pgfmathprintnumber{\pgfmathresult}}};
    \pgfmathparse{cos(\myn)} \node[anchor=west] at (DEG/C/\myn) {\texttt{\pgfmathprintnumber{\pgfmathresult}}};
    \pgfmathparse{tan(\myn)} \node[anchor=west] at (DEG/T/\myn) {\texttt{\pgfmathprintnumber{\pgfmathresult}}};

  }

\end{tikzpicture}

\end{document}

enter image description here

Best Answer

I don't know with pgfmath; with expl3 you can compile your table like this:

\documentclass{article}
\usepackage[margin=1cm]{geometry}

\usepackage{array,siunitx}

\sisetup{
  add-decimal-zero,
  round-precision=5,
  round-mode=places,
  round-integer-to-decimal,
  group-digits=false,
  detect-all,
}

\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\trigtable}{ }
 {
  \__aellett_do_trig:
  \begin{tabular}{r *{3}{ >{\ttfamily}r }}
  & \multicolumn{1}{c}{$\sin$}
  & \multicolumn{1}{c}{$\cos$}
  & \multicolumn{1}{c}{$\tan$}
  \\
  \tl_use:N \l__aellett_body_tl
  \end{tabular}
 }

\tl_new:N \l__aellett_body_tl

\cs_new:Npn \aellett_compute:nn #1 #2
 {
  \num { \fp_to_decimal:n { \fp_eval:n { round ( #1(#2) , 5 ) } } }
 }

\cs_new_protected:Npn \__aellett_do_trig:
 {
  \tl_clear:N \l__aellett_body_tl
  \int_step_inline:nnnn { 1 } { 1 } { 89 }
   {
    \tl_put_right:Nn \l__aellett_body_tl { $##1^\circ$ & }
    \tl_put_right:Nx \l__aellett_body_tl
     { 
      \aellett_compute:nn { sind } { ##1 } &
      \aellett_compute:nn { cosd } { ##1 } &
      \aellett_compute:nn { tand } { ##1 } 
     }
    \int_compare:nTF { \int_mod:nn { ##1 } { 5 } == 0 }
     {
      \tl_put_right:Nn \l__aellett_body_tl { \\[1ex] }
     }
     {
      \tl_put_right:Nn \l__aellett_body_tl { \\ }
     }
   }
  % 90 degrees
  \tl_put_right:Nx \l__aellett_body_tl
   {
    $90^\circ$ &
    \aellett_compute:nn { sind } { 90 } &
    \aellett_compute:nn { cosd } { 90 } &
    --- 
   }

 }

\ExplSyntaxOff

\begin{document}
\tiny
\trigtable

\end{document}

Here's the start:

start

And here's the end, just to show what happens at 89 degrees:

end

I used five digits for comparison with the value bc returns for the tangent of 89 degrees:

57.28996163075942465214

Related Question