我想要在 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
会将其迭代的内容分组。有以下几种选择:
\pgfplotsforeachungrouped\k in{0,...,10}
如果继续加载则使用pgfplots
。- 将求和的宏设为全局宏。可以工作,但效果不佳。
- 只需使用普通
\loop ... \repeat
命令即可。这已经使用过这里声明一个 pgf 函数sum
。 - 使用其他工具。
这明确说明了第三种选择。
\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}
优点
- 没有组,但变量在本地设置
tikzpicture
- 不存在破坏现有宏的风险
- 使用 15 位小数进行计算
缺点
- 有点冗长
- 只能使用“纯数字”