Skip to content
Permalink
Browse files
Add "use fpu reciprocal" to avoid loss of precision
This code has been contributed by Schrödinger's cat
See https://tex.stackexchange.com/a/529159/38080

Use it as a key in paths or in "circuitikz" environments when needed
  • Loading branch information
Rmano committed Feb 20, 2020
1 parent 4aded6e commit 00966c45c42b464fab5429f89f2b7fb414e9b3f7
Showing with 16 additions and 0 deletions.
  1. +1 −0 tex/circuitikz.sty
  2. +14 −0 tex/pgfcircutils.tex
  3. +1 −0 tex/t-circuitikz.tex
@@ -28,6 +28,7 @@
% latex' which we have lost in the transition
%
\usetikzlibrary{arrows.meta, bending}
\usetikzlibrary{fpu} % may be needed for use fpu reciprocal (v1.0.1)

% The options are listed in the manual in this order

@@ -65,5 +65,19 @@
\def\ctikztextnot#1{$\overline{\hbox{#1}}$}
\fi\fi\fi

%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% switch to use fpu in reciprocal scale transformations
%%
%% this code has been contributed by Schrödinger's cat
%% https://tex.stackexchange.com/a/529159/38080
%%
\tikzset{use fpu reciprocal/.code={%
\def\pgfmathreciprocal@##1{%
\begingroup
\pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}%
\pgfmathparse{1/##1}%
\pgfmath@smuggleone\pgfmathresult
\endgroup
}}}%

\endinput
@@ -19,6 +19,7 @@
\startmodule[circuitikz]
\usetikzlibrary[calc]
\usetikzlibrary[arrows.meta, bending]
\usetikzlibrary[fpu] % may be needed for use fpu reciprocal (v1.0.1)

\unprotect

3 comments on commit 00966c4

@hmenke

This comment has been minimized.

Copy link

@hmenke hmenke replied Aug 8, 2021

Please correct this code to use this:

\pgfqkeys{/circuitikz}{use fpu reciprocal/.code={%
    \def\pgfmathreciprocal@##1{%
      \begingroup
        \pgfmathfloatparsenumber{##1}%
        \pgfmathfloatreciprocal@{\pgfmathresult}%
        \pgfmathfloattofixed@{\pgfmathresult}%
        \pgfmath@smuggleone\pgfmathresult
      \endgroup
    }}}%

As I've already noted on the PGF bugtracker the original version of use fpu reciprocal is extremely inefficient, because on every invocation it loads the entire FPU and reparses an expression that is already know to be a number. By using the internal FPU functions we can sidestep all of this and achieve a speedup of about 3x.

In the example below I spin every function for identical input 10000 times. The “lengths” are in seconds, i.e. 2.4336pt = 2.4336 seconds.

screenshot

\documentclass{article}
\usepackage{tikz}
\usepgflibrary{fpu}
\begin{document}
\makeatletter
\pgfqkeys{/pgf}{use fpu reciprocal/.code={%
    \def\pgfmathreciprocal@##1{%
      \begingroup
      \pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}%
      \pgfmathparse{1/##1}%
      \pgfmath@smuggleone\pgfmathresult
      \endgroup
    }}}%
\pgfqkeys{/pgf}{use fpu reciprocal fast/.code={%
    \def\pgfmathreciprocal@##1{%
      \begingroup
        \pgfmathfloatparsenumber{##1}%
        \pgfmathfloatreciprocal@{\pgfmathresult}%
        \pgfmathfloattofixed@{\pgfmathresult}%
        \pgfmath@smuggleone\pgfmathresult
      \endgroup
    }}}%

\begingroup
\pgfkeys{/pgf/use fpu reciprocal}
\pdfresettimer
\foreach \i in {1,...,10000} {
  \pgfmathparse{1/0.0001234}
}
use fpu reciprocal: \the\dimexpr\pdfelapsedtime sp\relax
\endgroup

\begingroup
\pgfkeys{/pgf/use fpu reciprocal fast}
\pdfresettimer
\foreach \i in {1,...,10000} {
  \pgfmathparse{1/0.0001234}
}
use fpu reciprocal (fast): \the\dimexpr\pdfelapsedtime sp\relax
\endgroup

\begingroup
\pgfkeys{/pgf/fpu/install only={reciprocal}}
\pdfresettimer
\foreach \i in {1,...,10000} {
  \pgfmathparse{1/0.0001234}
}
fpu/install only: \the\dimexpr\pdfelapsedtime sp\relax
\endgroup

\makeatother

\end{document}
@Rmano

This comment has been minimized.

Copy link
Collaborator Author

@Rmano Rmano replied Aug 14, 2021

Thanks! I will add this as soon as the end of my vacations... (too early, I fear ;-))

@Rmano

This comment has been minimized.

Copy link
Collaborator Author

@Rmano Rmano replied Aug 15, 2021

Anyway, with any recent Tikz, circuitikz will use the internal function:

\pgfkeysifdefined{/pgf/fpu/install only/.@cmd}{%
\pgfqkeys{/pgf}{use fpu reciprocal/.code={\pgfkeys{/pgf/fpu/install only={reciprocal}}}}%
}{%
\pgfqkeys{/pgf}{use fpu reciprocal/.code={%
\def\pgfmathreciprocal@##1{%
\begingroup
\pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}%
\pgfmathparse{1/##1}%
\pgfmath@smuggleone\pgfmathresult
\endgroup
}}}%
}

...so probably it's already using your code most of the time (I think!).

Please sign in to comment.