7

It seems that one can't add \global before a \pgfmathsetmacro as that yields:

You can't use a prefix with `\begingroup'.

But that is the functionality I need here.

I am trying to compute the average of the integers in a list. In the MWE the list I have is

\newcommand*{\MyData}{3,7,X,Y,8,9,Z}%

and the \typeout messages show:

**** NumberOfValidEnteries=1, \AverageValue=3.0
**** NumberOfValidEnteries=2, \AverageValue=3.5
**** NumberOfValidEnteries=3, \AverageValue=2.66666
**** NumberOfValidEnteries=4, \AverageValue=2.25

So it seems as if the \pgfmathsetmacro is working except it is not saving its state between successive iterations of the \foreach, which is exactly what the \global was there for in the first place.

Code:

\documentclass{article}
\usepackage{tikz}
\usepackage{xstring}

% http://tex.stackexchange.com/questions/50111/how-to-check-if-the-value-of-a-parameter-is-a-number
\newcommand*{\IfIsInteger}[3]{%
    \IfStrEq{#1}{ }{%
        #3% is a blank string
    }{%
        \IfInteger{#1}{#2}{#3}%
    }%
}%

\newcommand*{\MyData}{3,7,X,Y,8,9,Z}%

\newcommand*{\AverageValue}{0}
\newcounter{NumberOfValidEnteries}
\newcommand*{\ComputeAverage}[1]{%
    %% Initialize (in case this is used more than once)
    \renewcommand*{\AverageValue}{0}
    \setcounter{NumberOfValidEnteries}{0}%
    %
    \edef\ExpandedDataEnteries{#1}% So that #1 can be a list or a macro defined list.
    \foreach \NewData in \ExpandedDataEnteries {%
        \IfIsInteger{\NewData}{%
            %\global% <---- I need this ????
            \pgfmathsetmacro{\AverageValue}{%  
                (\AverageValue * \arabic{NumberOfValidEnteries} + \NewData) /
                (\arabic{NumberOfValidEnteries} + 1)
            }%
            \stepcounter{NumberOfValidEnteries}%
            \typeout{**** NumberOfValidEnteries=\arabic{NumberOfValidEnteries}, \string\AverageValue=\AverageValue}%
        }{%
            % Not integer data so skip it
        }%
    }%
}

\begin{document}
    \ComputeAverage{\MyData}%
    Average of integers in ``\MyData" is ``\AverageValue".
\end{document}
  • 4
    \pgfmathsetmacro\temp{...}\global\let\AverageValue\temp – egreg Mar 8 '14 at 22:47
  • @egreg: Glad that that was easy. A bit embarrassed that I did not think of that. :-) – Peter Grill Mar 8 '14 at 22:48
9

You can legally place \global only before an assignment command:

\global\def
\global\let
\global\mathchardef
\global\catcode
\global\advance

and so on. One should note that \global wants and looks for a suitable command following it, doing expansion. For instance, etoolbox defines

\newrobustcmd{\cslet}[2]{%
  \expandafter\let\csname#1\endcsname#2}

so \global\cslet{foo}{\bar} is legal, because it will become

\global\expandafter\let\csname foo\endcsname\bar

after the first expansion, but since \expandafter is expandable, \global triggers its expansion and you get \global\let\foo\bar as wanted.

On the other hand, \pgfmathsetmacro is defined in pgfmathcalc.code.tex by

\def\pgfmathsetmacro#1#2{%
  \begingroup%
    \pgfmathparse{#2}%
        \let#1=\pgfmathresult
    \pgfmath@smuggleone{#1}%
  \endgroup%
}

so one can definitely not add \global in front of it.

The easiest workaround is to say

\pgfmathparse
  (\AverageValue * \arabic{NumberOfValidEnteries} + \NewData) /
   (\arabic{NumberOfValidEnteries} + 1)
  }%
\global\let\AverageValue\pgfmathresult

since \pgfmathparse stores the result in \pgfmathresult.

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.