Best way to store the sum of few numbers inside a foreach cycle
The problem is that the ordinary \foreach
puts the stuff it is iterating over in groups. There are a few options:
- Use
\pgfplotsforeachungrouped\k in{0,...,10}
instead if you keep loadingpgfplots
. - Make the macro for the sum global. Works but isn't great.
- Just use the ordinary
\loop ... \repeat
command. This has been used here to declare a pgf functionsum
. - Use other tools.
This illustrates the third option explicitly.
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{arrows.meta}
\usepackage[utf8]{inputenc} %utile per scrivere direttamente in caratteri accentuati
\begin{document}
\begin{tikzpicture}
% if you ever use the calc library you may want to avoid using `\n`, `\x` and
% \y for macros but here it is fine.
\pgfmathsetmacro{\n}{5}
\draw[-Latex](0,0)--(\n+.5,0);
\draw[scale=1,domain=0:\n,smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
\edef\k{0}
\edef\TotalSquareDiff{0}
\pgfmathsetseed{1}% so that others can cross check
\loop
\pgfmathsetmacro{\x}{5*\k/10}
\pgfmathsetmacro{\Y}{exp(-\x)}
\pgfmathsetmacro{\y}{exp(-\x)+rand/3}
\pgfmathsetmacro{\diff}{\y-\Y}
\pgfmathsetmacro{\Diff}{100*(\y-\Y)}
\pgfmathsetmacro{\squareddiff}{\diff*\diff}
\fill(\x,\y)circle[radius=1pt];
\ifdim0pt<\Diff pt\relax
\node[scale=.25,above]at(\x,\y+.1){$(x_{\k},y_{\k})$};
\else
\node[scale=.25,below]at(\x,\y-.1){$(x_{\k},y_{\k})$};
\fi
\draw[dotted](\x,\y)--(\x,\Y);
\node[scale=.2]at(\x,-1.25){$y_{\k}-f(x_{\k})$};
\node[scale=.25]at(\x,-1.5){$\diff$};
\node[scale=.2]at(\x,-1.75){$(y_{\k}-f(x_{\k}))^2$};
\node[scale=.25]at(\x,-2){$\squareddiff$};
\pgfmathsetmacro{\TotalSquareDiff}{\TotalSquareDiff+\squareddiff}%
\edef\k{\the\numexpr\k+1}
\ifnum\k<11
\repeat
\node at(2.5,-3){$\sum\limits_{k}^n(y_k-f(x_k))^2=\pgfmathprintnumber\TotalSquareDiff$};
\end{tikzpicture}
\end{document}
Here is a solution using remember
and evaluate
:
\documentclass{standalone}
\usepackage{amssymb} %maths
\usepackage{amsmath} %maths
\usepackage{booktabs}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{ifthen}
\usetikzlibrary{arrows.meta}
\usepackage[utf8]{inputenc} %utile per scrivere direttamente in caratteri accentuati
\begin{document}
\begin{tikzpicture}
\pgfmathsetmacro{\n}{5}
\draw[-Latex](0,0)--(\n+.5,0);
\draw[scale=1,domain=0:\n,smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
\foreach \k[
evaluate=\k as \x using 5*\k/10,
evaluate=\x as \Y using exp(-\x),
evaluate=\x as \y using exp(-\x)+rand/3,
evaluate=\y as \diff using \y-\Y,
evaluate=\diff as \Diff using 100*\diff,
evaluate=\diff as \squareddiff using (\diff)^2,
remember=\totsd as \totsd (initially 0), % fake sum
evaluate=\squareddiff as \totsd using \totsd+\squareddiff, % true sum
] in {0,...,10}
{
\fill[](\x,\y)circle(1pt);
\pgfmathsetmacro\mypos{0<\Diff?"south":"north"}
\node[scale=.25,anchor=\mypos]at(\x,{\y+(0<\Diff?+1:-1)*.1}){$(x_{\k},y_{\k})$};
\draw[dotted](\x,\y)--(\x,\Y);
\node[scale=.2]at(\x,-1.25){$y_{\k}-f(x_{\k})$};
\node[scale=.25]at(\x,-1.5){$\diff$};
\node[scale=.2]at(\x,-1.75){$(y_{\k}-f(x_{\k}))^2$};
\node[scale=.25]at(\x,-2){$\squareddiff$};
\node[scale=.18]at(\x,-2.25){$\sum\limits_{i=1}^{\k}(y_i-f(x_i))^2$};
\node[scale=.25]at(\x,-2.5){$\totsd$};
}
\end{tikzpicture}
\end{document}
Here's with “other tools”. The macro \fpshow
has an optional argument to use a certain number of decimal digits (rounded), default 2. Just to show the feature, I printed the sum of the squared differences rounded to four digits.
\documentclass{article}
\usepackage{amsmath} %maths
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{xparse,xfp}
\usepackage{ifthen}
\usetikzlibrary{arrows.meta}
\pgfplotsset{compat=1.17}
\ExplSyntaxOn
\NewDocumentCommand{\fpset}{mm}
{
\fp_if_exist:cF { l__yngabl_#1_fp } { \fp_new:c { l__yngabl_#1_fp } }
\fp_set:cn { l__yngabl_#1_fp } { #2 }
}
\NewExpandableDocumentCommand{\fpuse}{m}
{
\fp_use:c { l__yngabl_#1_fp }
}
\NewExpandableDocumentCommand{\fpshow}{O{2}m}
{
\fp_eval:n { round(\fp_use:c { l__yngabl_#2_fp },#1) }
}
\NewDocumentCommand{\xforeach}{mmm}
{
\cs_set:Nn \__ybgabl_xforeach:n { #3 }
\int_step_function:nnN { #1 } { #2 } \__ybgabl_xforeach:n
}
\NewExpandableDocumentCommand{\fpcompareTF}{mmm}
{
\fp_compare:nTF { #1 } { #2 } { #3 }
}
\ExplSyntaxOff
\begin{document}
\begin{tikzpicture}
\fpset{n}{5}
\draw[-Latex](0,0)--(\fpuse{n}+.5,0);
\draw[scale=1,domain=0:\fpuse{n},smooth,variable=\X,red,thick] plot ({\X},{exp(-\X)});
\fpset{total}{0}% initialize the total
\xforeach{0}{10}{
\fpset{x}{5*\fpeval{#1/10}}
\fpset{diff}{(-1)**randint(1,2)*rand()/3}
\fpset{y}{exp(-\fpuse{x})}
\fpset{sqdiff}{\fpuse{diff}*\fpuse{diff}}
\fpset{total}{\fpuse{total}+\fpuse{sqdiff}}
\fill[](\fpuse{x},\fpeval{\fpuse{y}+\fpuse{diff}}) circle(1pt);
\fpcompareTF{\fpuse{diff}>0}
{ \node[scale=.25,above] at (\fpuse{x},\fpuse{y}+\fpuse{diff}+.1){$(x_{#1},y_{#1})$}; }
{ \node[scale=.25,below] at (\fpuse{x},\fpuse{y}+\fpuse{diff}-.1){$(x_{#1},y_{#1})$}; }
\draw[dotted](\fpuse{x},\fpuse{y})--(\fpuse{x},\fpeval{\fpuse{y}+\fpuse{diff}});
\node[scale=.2]at(\fpuse{x},-1.25){$y_{#1}-f(x_{#1})$};
\node[scale=.25]at(\fpuse{x},-1.5){$\fpshow{diff}$};
\node[scale=.2]at(\fpuse{x},-1.75){$(y_{#1}-f(x_{#1}))^2$};
\node[scale=.25]at(\fpuse{x},-2){$\fpshow{sqdiff}$};
}
\node[]at(2.5,-3){$\displaystyle\sum_{k=0}^n(y_k-f(x_k))^2=\fpshow[4]{total}$};
\end{tikzpicture}
\end{document}
Advantages
- No group, but variables are set locally in the
tikzpicture
- No risk to clobber existing macros
- Computations are made with 15 decimal digits
Disadvantages
- A bit more verbose
- Only “pure numbers” can be used