pgf-tikz / pgf

A Portable Graphic Format for TeX
https://pgf-tikz.github.io/
1.14k stars 108 forks source link

Division by zero in trigonometric functions fails with "Runaway argument" when using FPU #1027

Open Rmano opened 3 years ago

Rmano commented 3 years ago

When using the fpu library, division by zero in trigonometric functions acts very strangely. Original report is here: https://tex.stackexchange.com/questions/602553/pgfplots-error-when-graphing-trig-function-when-is-inside (but the MWE is too complex there)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fpu}
\begin{document}
    \typeout{Version\space\pgfversion}
    \tikzset{declare function={x=0;}}
    \pgfkeys{/pgf/fpu=true}
    \pgfmathparse{1/x}\typeout{\pgfmathresult}
    \pgfmathparse{sin(1/x)}\typeout{\pgfmathresult}
\end{document}

Commenting out the \pgfkeys{/pgf/fpu=true} the two following lines give the expected "you can't divide by zero" error. With the fpu on, the first pgfmathparse gives no error (I imagine is returning a NaN, the typeout says 4Y0.0e0]), but the second one "explodes" with:

Runaway argument?
inf\relax \let \pgfmathfloat@loc@TMPa =\pgfmathresult \pgfmathfloattoint \ETC.
! File ended while scanning use of \pgfmathfloattoint@@.
<inserted text> 
                \par

The reported version is Version 3.1.9a

muzimuzhi commented 3 years ago

Caused by that \pgfmathfloattoint doesn't accept one of inf, -inf, and nan to be its #1. https://github.com/pgf-tikz/pgf/blob/e9c22dc9fe48f975b7fdb32181f03090b3747499/tex/generic/pgf/math/pgfmathfloat.code.tex#L395-L404

muzimuzhi commented 3 years ago
  • \pgfmathparse{sin(1/0)} will call \pgfmathfloatmod@{4Y0.0e0]}{\pgfmathfloatTRIG@NUM}, which will call \pgfmathfloattoint{4Y0.0e0]}.

A complete "call stack" of \pgfmathparse{sin(1/0)}, to help decide where the guards could be added:

\pgfmathparse{sin(1/0)}
  \pgfmathsin@{4Y0.0e0]} % with fpu, \pgfmathsin@ is let to \pgfmathfloatsin@
    \pgfmathfloatTRIG@\pgfmath@basic@sin@{4Y0.0e0]}
      \pgfmathfloatmodknowsinverse@{4Y0.0e0]}{\pgfmathfloatTRIG@NUM}{\pgfmathfloatTRIG@NUM@INV}
        \pgfmathfloatmod@{4Y0.0e0]}{\pgfmathfloatTRIG@NUM}
          \pgfmathfloattoint{4Y0.0e0]}
            \pgfmathfloattoint@@{inf} % throw error
Rmano commented 3 years ago

I am not sure if my comment makes sense, but --- I think that the idea is that a trigonometric function receiving an Inf, -Inf or NaN should return NaN. Python says math domain error if fed with sin(math.inf) and NumPy assigns a NaN:

In [11]: np.sin([math.inf])                                                     
<ipython-input-11-e601ce124a7b>:1: RuntimeWarning: invalid value encountered in sin
  np.sin([math.inf])
Out[11]: array([nan])