在 foreach 循环中存储几个数字之和的最佳方法

在 foreach 循环中存储几个数字之和的最佳方法

我想要在 foreach 循环中计算某些值的总和,如下例所示:

\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 in {0,...,10}
{
\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}{abs(\diff^2)}
\fill[](\x,\y)circle(1pt);
\ifthenelse{0<\Diff}{\node[scale=.25,above]at(\x,\y+.1){$(x_{\k},y_{\k})$};
}{\node[scale=.25,below]at(\x,\y-.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[]at(2.5,-3){$\sum\limits_{k}^n(y_k-f(x_k))^2=?$};
}
\end{tikzpicture}
\end{document}

答案1

问题在于,普通方法\foreach会将其迭代的内容分组。有以下几种选择:

  1. \pgfplotsforeachungrouped\k in{0,...,10}如果继续加载则使用pgfplots
  2. 将求和的宏设为全局宏。可以工作,但效果不佳。
  3. 只需使用普通\loop ... \repeat命令即可。这已经使用过这里声明一个 pgf 函数sum
  4. 使用其他工具。

这明确说明了第三种选择。

\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}

在此处输入图片描述

答案2

remember以下是使用和 的解决方案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}

答案3

这是“其他工具”。该宏\fpshow有一个可选参数,用于使用一定数量的小数(四舍五入),默认值为 2。为了展示该功能,我打印了四舍五入为四位数字的平方差之和。

\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}

优点

  1. 没有组,但变量在本地设置tikzpicture
  2. 不存在破坏现有宏的风险
  3. 使用 15 位小数进行计算

缺点

  1. 有点冗长
  2. 只能使用“纯数字”

在此处输入图片描述

相关内容