TikZ fpu seems to be inaccurate

I'am using a macro from here (thanks to Schrödinger's cat). See my MWE:

\documentclass{scrartcl}
\usepackage{tikz}
\usetikzlibrary{fpu}
\newcommand\pgfmathparseFPU[1]{
\begingroup
\pgfkeys{
/pgf/fpu,
/pgf/fpu/output format = fixed
}
\pgfmathparse{#1}
\pgfmathsmuggle
\pgfmathresult
\endgroup}

\begin{document}

%data values:
\def\UABmValues{{14.9, 15.8, 17.7, 18.3, 19, 20, 21.1, 22.2, 24.3, 26.9, 30.1}}

%prints the result to the console:
\foreach[count = \i from 0] \k in {30, 35, ..., 80}
{
\pgfmathsetmacro{\UABmValues}{\UABmValues[\i]}
\pgfmathparseFPU{-25500 / (\UABmValues / 1000 - 255 / 52) - 5200 - 3.0897 / 8 * \k}\i, \pgfmathresult\\
}

\end{document}


Gives:

1. 4.414001000000000
2. 3.483002000000000
3. 3.652002000000000
4. 2.221002000000000
5. 0.990002
6. 0.159003
7. -0.571997
8. -1.302997000000000
9. -1.033997000000000
10. -0.064996
11. 1.304004000000000

When I do the same, let say, with MATLAB:

    UABmValues = [14.9 15.8 17.7 18.3 19 20 21.1 22.2 24.3 26.9 30.1];
R = 30 : 5 : 80;

%prints the result to the console:
for j = 1 : 11

result = -25500 / (UABmValues(j) / 1000 - 255 / 52) - 5200 - 3.0897 / 8 * R(j);
fprintf('j=%d, ', j)
fprintf('%d.\n', result)

end


Than I get following:

1. 4.261621e+00.
2. 3.290914e+00.
3. 3.388431e+00.
4. 2.098301e+00.
5. 9.151911e-01.
6. 5.300458e-02.
7. -7.017887e-01.
8. -1.456052e+00.
9. -1.139024e+00.
10. -2.840543e-01.
11. 1.217927e+00.

The difference is huge.

Why is it so? Any suggestions how to solve it with fpu, if at least possible?

• The PGF FPU uses TeX \dimen registers for calculations, so it has the same accuracy restrictions. The smallest representable difference in a TeX \dimen is 1sp, which is 0.00002pt (try \the\dimexpr1sp\relax). If you need more accuracy, try the LaTeX3 FPU (loaded by the xfp package). Dec 26 '19 at 12:32
• @PhelypeOleinik fp gives good results ... but I agree with you xfp seems to be the good way. Perhaps lua is the better way ? Dec 26 '19 at 13:15
• @AlainMatthes Yes, fp has a higher accuracy than the LaTeX3 FPU. (The latter conforms to the IEEE-754 standard, accurate to 16 significant digits or so). But xfp (and Lua, for that matter) is fully expandable, while fp is not. I'm not sure about Lua's accuracy. But my job description is to advertise expl3, so I had to suggest that ;-) Dec 26 '19 at 13:19
• @PhelypeOleinik I agree with you xfp is fully expandable. I use fp because it was the only solution several years ago.I think you have wit lua IEEE 754 double precision floating point Dec 26 '19 at 14:42

The PGF floating point module is inaccurate, as it uses TeX arithmetic, so it doesn't go beyond five decimal digits. It is not meant as an all-purpose floating point arithmetic tool, but just to do typesetting.

Use xfp.

\documentclass{article}
\usepackage{tikz}
\usepackage{xfp}

\begin{document}

%data values:
\def\UABmValues{{14.9, 15.8, 17.7, 18.3, 19, 20, 21.1, 22.2, 24.3, 26.9, 30.1}}

%prints the result to the console:
\foreach[count = \i from 0] \k in {30, 35, ..., 80}
{
\pgfmathsetmacro{\UABmValues}{\UABmValues[\i]}
\i, $\fpeval{-25500 / (\UABmValues / 1000 - 255 / 52) - 5200 - 3.0897 / 8 * \k}$\par
}

\end{document}


• This is the first I've heard of the xfp package. Are there any known side effects (for instance, speed)? Dec 27 '19 at 19:57

You can try fp, xfp (see egreg's answer) or lua

1) update : version with lua

% !TEX TS-program = lualatex

\documentclass{scrartcl}
\usepackage{pgffor,pgfmath}
\def\luafun#1#2{
\directlua{
x = #1;
y = #2;
r=-25500/(x/1000-255/52)-5200-3.0897/8*y
tex.print(r)}
}

\begin{document}
\def\UABmValues{{14.9, 15.8, 17.7, 18.3, 19, 20, 21.1, 22.2, 24.3, 26.9, 30.1}}

\foreach[count = \i from 0] \k in {30, 35, ..., 80}
{
\pgfmathsetmacro{\myval}{\UABmValues[\i]}%
\luafun{\myval}{\k}\par
}

\end{document}


2) old version with fp

\documentclass{scrartcl}
\usepackage{tikz,fp}
\newcommand\pgfmathparseFP[1]{
\begingroup
\FPeval\pgfmathresult{(#1)}
\pgfmathsmuggle
\pgfmathresult
\endgroup
}

\begin{document}

%data values:
\def\UABmValues{{14.9, 15.8, 17.7, 18.3, 19, 20, 21.1, 22.2, 24.3, 26.9, 30.1}}

%prints the result to the console:
\foreach[count = \i from 0] \k in {30, 35, ..., 80}
{
\pgfmathsetmacro{\myval}{\UABmValues[\i]}%
\pgfmathparseFP{-25500/(\myval/1000-255/52)-5200-3.0897/8*\k}\i, \pgfmathresult\par
}

\end{document}


• What is the drawback of doing so per default? I mean, pgfmath could be patched like this. Dec 26 '19 at 14:04
• @OlegLobachev maintenance. The maintainers of TikZ don't want to use expl3 and have their reasons for doing so. Dec 26 '19 at 14:20
• @OlegLobachev Balance between speed and precision. pgfmath is used usefully by some libraries and precision is not always as important Dec 26 '19 at 14:25
• I don't know how to use more digits with lua Dec 26 '19 at 15:37
• @OlegLobachev One of the reasons is performance. It would essentially double the load time. See here for a discussion.
– user194703
Dec 26 '19 at 15:50

An implementation with the CAS Sage(math) and SageTeX:

I use arara: sagetex for compiling.

% arara: pdflatex
% arara: sagetex
% arara: pdflatex

\documentclass{scrartcl}
\usepackage{sagetex, amsmath}
\usepackage{tikz}
\usetikzlibrary{fpu}
\newcommand\pgfmathparseFPU[1]{
\begingroup
\pgfkeys{
/pgf/fpu,
/pgf/fpu/output format = fixed
}
\pgfmathparse{#1}
\pgfmathsmuggle
\pgfmathresult
\endgroup}

\begin{document}
%data values:
\def\UABmValues{{14.9, 15.8, 17.7, 18.3, 19, 20, 21.1, 22.2, 24.3, 26.9, 30.1}}

\section{pgfmath}
\foreach[count = \i from 0] \k in {30, 35, ..., 80}
{
\pgfmathsetmacro{\UABmValues}{\UABmValues[\i]}
\pgfmathparseFPU{-25500 / (\UABmValues / 1000 - 255 / 52) - 5200 - 3.0897 / 8 * \k}\noindent\i, \UABmValues, \pgfmathresult \\
}

\section{SageTeX}
\subsection{Sage-Output}
$\sagestr{MyOut}$

\subsection{From sageblock or sagesilent}
\begin{sageblock}
Val = ([14.9, 15.8, 17.7, 18.3, 19, 20, 21.1, 22.2, 24.3, 26.9, 30.1])
## Test:
#print Val[1]
#print len(Val)

# Function
f(x,y) = -25500/(x/1000 - 255/52) -5200 -3.0897/8 *(30+5*y)

# Short Output
#for i in range (len(Val)): print i,',',float(Val[i]),',', f(Val[i],i)

# Better Output
data = [(i,  float(Val[i]), f(Val[i],i)) for i in range(len(Val))]
data_str = [',   '.join(map(str, t)) for t in data]
data_str = '\n'.join(data_str)

MyOut = latex(data_str)
#print data_str
\end{sageblock}
\end{document}