6

I'd like to pick a number from my array inside a loop. The first argument is a "starting" value which increments by 1 for each iteration based on the second and third argument (\qa). The maximum number of iterations can be determined by the second argument (\eval@limit). The other maximum value can be determined by the value of the third argument (\arbitraryarrayvalue).

I'm running into some issues using my array inside \pgfmathdeclarefunction. Specifically: The first case, the easy one, is to simply put:

\pgfmathparse{\myarray[\arbitraryarrayvalue]}
\pgfmath@smuggleone\pgfmathresult

Before closing the group. It turns out I can't look inside the array:

Paragraph ended before \pgfflt@readlowlevelfloat was complete.
<to be read again> 
                   \par 

So looking at the existing questsions I found one related question to \pgfflt@readlowlevelfloat, at How do I use pgfmathdeclarefunction to create define a new pgf function?.

I couldn't make the inference from that question to the solution of mine.

So second case: if I use the array inside my Expl3 solution for comparisons (this solution you will also find in the code below), I get an error like this one:

File ended while scanning use of \__fp_parse_after:ww.
Emergency stop.
==> Fatal error occurred, no output PDF file produced!

So judging from the fact they both refer to "file ended while doing something", I suspect these macro's keep reading further and expanding further until the document ends, which I usually solve with a well-placed \relax. I've tried adding that all over the place (inside the comparison, after it, about the array, etc.), but I can't seem to get rid of the error.

Possibly not so related but maybe a general solution outside expl3 would be the answer (?) regardless, I would like to see how a such general solution to break the loop would look like outside expl3. :-)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fpu}

\usepackage{expl3}

\ExplSyntaxOn
\cs_new:Npn \breakloop #1 #2
  {
    \fp_compare:nNnT { #1 } > { #2 }
      { \breakforeach }
  }
\ExplSyntaxOff

\global\def\myarray{{5,10,15,20,25,30,35,40,45,50,55,60}}

\makeatletter
\pgfmathdeclarefunction{blah}{3}{%
  \begingroup
    \pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}
    \pgfmathparse{#1} % starting value
    \edef\qa{\pgfmathresult}
    \pgfmathparse{#2} % maximum amount of loops
    \edef\eval@limit{\pgfmathresult}
    \pgfmathparse{#3+1} % maximum value of array
    \edef\arbitraryarrayvalue{\pgfmathresult}
    \foreach \i in {0,...,\eval@limit}
    {
      \pgfmathparse{\qa+1} % \qa += 1
      \global\edef\q@{\pgfmathresult} %
      \pgfmathparse{\q@} %
      \global\edef\qa{\pgfmathresult} %
      \breakloop{\qa}{\myarray[\arbitraryarrayvalue]}
    }
    \pgfmathparse{\qa}
    \pgfmath@smuggleone\pgfmathresult
  \endgroup
}
\makeatother
\begin{document}
\pgfmathparse{blah(1,1000,9)}\pgfmathresult    %

\pgfmathparse{\myarray[2]}\pgfmathresult
\end{document}
3
+50

This is solved by evaluating the array element first. Getting the element requires you pass an integer as an index, not a number in fixed point notation. I have moved the evaluation of the array element outside the loop as it does not vary with the iteration.

Sample output

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fpu}

\usepackage{expl3}

\ExplSyntaxOn
\cs_new:Npn \breakloop #1 #2
  {
    \fp_compare:nNnT { #1 } > { #2 }
      { \breakforeach }
  }
\ExplSyntaxOff

\gdef\myarray{{5,10,15,20,25,30,35,40,45,50,55,60}}

\makeatletter
\pgfmathdeclarefunction{blah}{3}{%
  \begingroup
    \pgfmathparse{#1} % starting value
    \edef\qa{\pgfmathresult}
    \pgfmathparse{#2} % maximum amount of loops
    \edef\eval@limit{\pgfmathresult}
    \pgfmathparse{#3+1} % maximum value of array
    \edef\arbitraryarrayvalue{\pgfmathresult}
    \pgfmathparse{\myarray[\arbitraryarrayvalue]}
    \edef\qb{\pgfmathresult}
    \pgfkeys{/pgf/fpu,/pgf/fpu/output format=fixed}
    \foreach \i in {0,...,\eval@limit}
    {
      \pgfmathparse{\qa+1} % \qa += 1
      \xdef\q@{\pgfmathresult} %
      \pgfmathparse{\q@} %
      \xdef\qa{\pgfmathresult} %
      \breakloop{\qa}{\qb}
    }
    \pgfmathparse{\qa}
    \pgfmath@smuggleone\pgfmathresult
  \endgroup
}
\makeatother
\begin{document}
\pgfmathparse{blah(1,1000,9)}\pgfmathresult    %

\pgfmathparse{\myarray[4]}\pgfmathresult
\end{document}
  • Nice addition of the shorthand notations \xdef and \gdef. I also noticed \gdef is unneeded for the array ? Which puzzles me a bit considering I just opened a new group, but hey, it works. – 1010011010 Jun 15 '14 at 19:36
  • The array is defined at outer level so persists in lower level groups. The global there could be useful if you later package this up in something else. – Andrew Swann Jun 16 '14 at 9:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.