
Я пытаюсь построить функцию, которая является суммой другой функции на основе параметра.
Известным примером этого является «сумма квадратов», однако функции, которые мне действительно нужны, не имеют явной формулы.
Следующий пример показывает результат, который я хотел бы получить, и метод, с помощью которого я хотел бы его получить, но который, очевидно, не дает правильного результата.
\documentclass[border=10]{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=1.9}
\begin{document}
% Explicit formula
\pgfmathdeclarefunction{explicit_sum}{1}{%
\pgfmathparse{(#1*(#1-1))/2}%
}
% The inner function
\pgfmathdeclarefunction{square}{1}{%
\pgfmathparse{#1*#1}%
}
% Compute the sum of another function
% Does not work...
\pgfmathdeclarefunction{manual_sum}{1}{%
%Parameter should be integral
\pgfmathtruncatemacro\cnt{#1}
\pgfmathsetmacro\ret{0}
\foreach \i in {1,...,\cnt} {
\pgfmathsetmacro\ret{\ret + sum(\i)}
}
\pgfmathparse{\ret}
}
\begin{tikzpicture}
\begin{axis}
% Expected
\addplot[samples at={1,...,10}] {explicit_sum(x)};
% Does not work
\addplot[samples at={1,...,10}] {manual_sum(x)};
\end{axis}
\end{tikzpicture}
\end{document}
решение1
Если разрешено создать «невидимую» таблицу для определения значений x, а затем выполнить вычисления в другом столбце, то можно сделать следующее.
\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
% Explicit formula
\pgfmathdeclarefunction{explicit_sum}{1}{%
\pgfmathparse{(#1*(#1-1))/2}%
}
\pgfplotstableset{
% define how the 'x' column shall be filled
% (in this case just with integers counting from 1)
create on use/x/.style={
create col/set list={1,...,100}
},
% -----
% now you can either create here a column with your function ...
create on use/fx/.style={
create col/expr={(\thisrow{x})^2}
},
% ... and then accumulate the values here ...
create on use/sum/.style={
create col/expr accum={
\pgfmathaccuma + \thisrow{fx}
}{0}, % <-- start with `0'
},
% -----
% ... or you accumulate directly with the function
create on use/sum2/.style={
create col/expr accum={
\pgfmathaccuma + (\thisrow{x})^2
}{0}, % <-- start with `0'
},
% -----
}
% here you create a new table using the columns you need and
% with the first mandatory argument you specify the number of elements
% the table should have
% (so either `sum2' is redundant or (`fx' and `sum') are redundant)
\pgfplotstablenew[
columns={x,fx,sum,sum2},
]{10}{\loadedtable}
\begin{document}
% % maybe it is useful to typeset the table for debugging purposes
% \pgfplotstabletypeset[
% columns={x,fx,sum,sum2},
% ]{\loadedtable}
\begin{tikzpicture}
\begin{axis}[
% added for debugging purposes or here to quicker check,
% it one gets the desired output
nodes near coords,
]
% Expected
\addplot+[samples at={1,...,10}] {explicit_sum(x)};
% when the table is created, you can use the columns here
\addplot table [x=x,y=sum] {\loadedtable};
\end{axis}
\end{tikzpicture}
\end{document}
решение2
TL; DR, объявление функции должно быть
\pgfmathdeclarefunction{manual_sum}{1}{%
\pgfmathfloattoint{#1}\let\cnt\pgfmathresult%
\pgfmathsetmacro\ret{0}%
\foreach\i in{1,...,\cnt}{%
\pgfmathsetmacro\ret{\ret+\i} % summing integer itself
%\pgfmathsetmacro\ret{\ret+square(\i)} % general case
\xdef\ret{\ret}%
}%
\pgfmathparse{\ret}%
}
В вашем коде есть две проблемы:
- Во-первых,
\foreach
вводит вложенную группировку и\ret
оказывается в ловушке группы. - Во-вторых, посколькуpgfplotsактивирует FPU,
\pgfmathtruncatemacro\cnt{#1}
заставит\cnt
быть1
.- (Это на самом делефлагв
#1
представительстве ФПУ.) - (флаг
1
(Обозначает положительное число.)
- (Это на самом делефлагв
Чтобы преодолеть первое препятствие, я обычно использую \xdef
контрабанду ценности. Также стоит отметить, чтоpgfplotsпредставляет \pgfplotsforeachungrouped
, который по сути является несгруппированной версией \foreach
.
Для решения второго препятствия необходимо внимательно изучить руководство и определить \pgfmathfloattoint{#1}\let\cnt\pgfmathresult
правильный способ выполнения работы.
это даст вам кривую, отличную от explicit_sum
, и тогда вы поймете, что #1*(#1-1)/2
это неверная формула.