pgf-tikz / pgf

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

Formatting numbers in math environment with fpu #1174

Open Addlai opened 2 years ago

Addlai commented 2 years ago

Brief outline of the bug

When using fpu to do calculations in the math environment, it seems that all numbers are printed as floating point, even if they are declared to be integers.

Integer variables can be explicitly printed as integers by invoking \pgfmathprintnumber, but this is cumbersome for intricate uses, and negates the purpose of declaring variables as integers in the first place.

Minimal working example (MWE)

\documentclass{amsart}

\usepackage{tikz}
\usetikzlibrary{math}

\begin{document}
\pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}
\pgfkeys{/pgf/number format/.cd,fixed,precision=2}

\tikzmath{
   int \foo,\foobar,\foobaz;
   \foo = 2;
   \foobar = \foo^10;
   \foobaz = \foo^20;
}

\begin{align*}
  \text{foobar} &= \foobar\\
  \text{foobaz} &= \foobaz\\
  \text{foobaz formatted} &= \pgfmathprintnumber{\foobaz}
\end{align*}

\end{document}
muzimuzhi commented 2 years ago

Sorry I didn't realize it was a bug when I saw and answered the original post on TeX-SX (https://tex.stackexchange.com/q/650081).

math library uses \pgfmathparse{int(<math expr>)} for integer assignments, but when fpu is active math function int won't return an integral number anymore, but a floating point number containing only the integer part of the function input.

Try this:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{math} % depends on fpu

\usepackage{regexpatch}

\makeatletter
\def\patch{%
\makeatletter
% replace two occurrences
\xpatchcmd*\tikz@math@doassignment
  {\tikz@math@ifvarinteger{##1}{\pgfmathparse{int(##2)}}{\pgfmathparse{##2}}}
  {%
    \tikz@math@ifvarinteger{##1}{%
      \pgflibraryfpuifactive{%
        \begingroup
          \pgfset{fpu/output format=float}%
          \pgfmathparse{##2}%
          \expandafter\pgfmathfloattoint\expandafter{\pgfmathresult}%
          \pgfmath@smuggleone\pgfmathresult
        \endgroup
      }{%
        \pgfmathparse{int(##2)}%
      }%
    }{\pgfmathparse{##2}}
  }
  {}{\PatchFailed}
\makeatother
}
\makeatother

\begin{document}
\def\header#1{\par\leavevmode\llap{\texttt{\detokenize{#1}}: }\ignorespaces}
\def\test{
  \header{\tikzmath}
  \tikzmath{
    int \a;
    \a = 2;      print \a;
    \a = \a + 1; print \a;
  }

  \header{\pgfmathparse}
  \pgfmathprint{2}
  \pgfmathprint{1+2}
  \pgfmathprint{int(1+2)}
}

\textbf{Before patch}
\pgfset{fpu=false, fpu/output format=float} \test
\pgfset{fpu=true}                           \test
\pgfset{fpu/output format=fixed}            \test

\textbf{After patch}
\patch
\pgfset{fpu=false, fpu/output format=float} \test
\pgfset{fpu=true}                           \test
\pgfset{fpu/output format=fixed}            \test
\end{document}

image

Note: The spurious spaces at the beginning of \tikzmath{print ...} outputs have been reported as #1175.