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}
1010011010
  • 6,357

1 Answers1

3

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}
Andrew Swann
  • 95,762
  • 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 09:12