我想绘制对数正态函数:
\documentclass{article}
\usepackage{pgfplots}
\begin{document}
\pgfmathdeclarefunction{lognormal}{2}{%
% \pgfkeys{/pgf/fpu=true}
\pgfmathparse{1/(x*#2*sqrt(2*pi))*exp(-((ln(x)-#1)^2)/(2*#2^2))}%
% \pgfmathresult
% \pgfkeys{/pgf/fpu=false}
}
\begin{tikzpicture}
\begin{axis}[ domain=0.01:10 ]
\addplot {lognormal(ln(5),0.02)};
\end{axis}
\end{tikzpicture}
\end{document}
即使函数具有中等值,它也会产生“维度太大”的错误。我猜问题出在中间值上exp()
。我/pgf/fpu=true
按照建议尝试过(在源代码中注释掉)在这个答案中但它没有帮助,甚至还使 PGF 更加混乱。后者可以通过替换lognormal(ln(5),0.02)
来验证lognormal(ln(5),1)
。
如何在 pgf 中绘制对数正态函数?我尝试用以下代码替换域中存在问题的部分:y ~ 0:
\pgfmathparse{1/(x*#2*sqrt(2*pi))*exp(ifthenelse((ln(x)-#1)/sqrt(#2) < -10, -100, -((ln(x)-#1)^2)/(2*#2^2)))}
如你所见,我没有在条件中使用平方,以避免溢出。但是,对于某些参数,使用该方程处理单个图表需要几秒钟,而处理包含许多图表的整个 Tex 文档则需要一分钟以上。有没有更快、更精确、更优雅的解决方案?
答案1
编辑2:
小包装纸被送到了加拿大运输安全局。因此,使用最新的 LaTeX 发行版的以下代码现在只是:
\documentclass{article}
\usepackage{pgfplots}
\usepackage{pgfmath-xfp}
\pgfmxfpdeclarefunction{lognormal}{3}
{exp(-((ln(#1) - #2)^2) / (2 * (#3)^2)) / (#1 * #3 * sqrt(2 * pi))}
\begin{document}
\begin{tikzpicture}
\begin{axis}[ domain=0.01:10, samples=100 ]
\addplot {lognormal(x,ln(5),0.02)};
\end{axis}
\end{tikzpicture}
\end{document}
编辑:
我创建了一个小包装器来定义pgfmath
函数l3fp
首次发布于此处有了它,这里的 MWE 可以归结为以下内容(\ExplSyntaxOn
和之间的内容\ExplSyntaxOff
是包装器):
\documentclass{article}
\usepackage{pgfplots}
\ExplSyntaxOn
\tl_new:N \l_pgffpeval_function_body_tl
\tl_new:N \l_pgffpeval_function_definition_tl
\int_new:N \l_pgffpeval_tmp_int
\cs_new_protected:Npn \pgffpeval_declare_function:nnn #1#2#3
{
\__pgffpeval_initialize_body:
\int_step_inline:nn {#2}
{
\tl_put_right:Nx \l_pgffpeval_function_body_tl
{
\exp_not:n { \pgfmathsetmacro } \exp_not:c { __pgffpeval_arg##1 }
{ \exp_not:n {####} ##1 }
}
}
\__pgffpeval_define_function:nnnn {#2} {#1} {#2} {#3}
}
\cs_new_protected:Npn \pgffpeval_declare_function_processed_args:nnnn #1#2#3#4
{
\__pgffpeval_initialize_body:
\int_zero:N \l_pgffpeval_tmp_int
\clist_map_inline:nn {#3}
{
\int_incr:N \l_pgffpeval_tmp_int
\tl_put_right:Nx \l_pgffpeval_function_body_tl
{
\exp_not:n { \pgfmathsetmacro }
\exp_not:c { __pgffpeval_arg \int_use:N \l_pgffpeval_tmp_int }
{ \exp_not:n {##1} }
}
}
\exp_args:NV
\__pgffpeval_define_function:nnnn \l_pgffpeval_tmp_int {#1} {#2} {#4}
}
\cs_new_protected:Npn \__pgffpeval_initialize_body:
{
\tl_set:Nn \l_pgffpeval_function_body_tl
{
\group_begin:
\pgfkeys{/pgf/fpu=true, /pgf/fpu/output~format=sci}%
}
}
\cs_new:Npn \__pgffpeval_process_function_aux:n #1 { \exp_not:n {## #1} }
\cs_new_protected:Npn \__pgffpeval_process_function:nnn #1#2#3
{
\exp_last_unbraced:Nx
\cs_set_protected:cpn
{
{ __pgffpeval_function_ #2 _cmd }
\int_step_function:nN {#1} \__pgffpeval_process_function_aux:n
}
{ \group_end: \exp_args:Nf \pgfmathparse { \fp_eval:n {#3} } }
}
\cs_new_protected:Npn \__pgffpeval_define_function:nnnn #1#2#3#4
{
\__pgffpeval_process_function:nnn {#1} {#2} {#4}
\tl_put_right:Nx \l_pgffpeval_function_body_tl
{
\use:x
{
\exp_not:c { __pgffpeval_function_ #2 _cmd }
\int_step_function:nN {#1} \__pgffpeval_define_function_aux:n
}
}
\exp_args:Nnno
\pgfmathdeclarefunction {#2} {#3} \l_pgffpeval_function_body_tl
}
\cs_new:Npn \__pgffpeval_define_function_aux:n #1
{ { \exp_not:c { __pgffpeval_arg#1 } } }
\NewDocumentCommand \pgfmathdeclarefpevalfunction { m m o m }
{
\IfValueTF {#3}
{ \pgffpeval_declare_function_processed_args:nnnn {#1} {#2} {#3} }
{ \pgffpeval_declare_function:nnn {#1} {#2} }
{#4}
}
\ExplSyntaxOff
\pgfmathdeclarefpevalfunction{lognormal}{3}
{exp(-((ln(#1) - #2)^2) / (2 * (#3)^2)) / (#1 * #3 * sqrt(2 * pi))}
\begin{document}
\begin{tikzpicture}
\begin{axis}[ domain=0.01:10, samples=100 ]
\addplot {lognormal(x,ln(5),0.02)};
\end{axis}
\end{tikzpicture}
\end{document}
输出和解释如下。
以下用于xfp
实际计算,并\pgfmathsetmacro
使用选项/pgf/fpu=true
和/pgf/fpu/output format=sci
在本地应用,以确保输入数字格式是可以理解的xfp
(因为pgfmath
当使用 FPU 时使用自定义的内部数字表示,而 无法理解xfp
)。
用于\romannumeral
确保\fpeval
在组关闭时完全完成,因此\argA
,,\argB
和\argC
不再具有正确含义。然后再次解析结果,以\pgfmathparse
确保在函数外部\pgfmathresult
保持正确的格式。pgf
\documentclass{article}
\usepackage{pgfplots}
\usepackage[]{xfp}
\begin{document}
\pgfmathdeclarefunction{lognormal}{3}{%
\begingroup
\pgfkeys{/pgf/fpu=true, /pgf/fpu/output format=sci}%
\pgfmathsetmacro\argA{#1}%
\pgfmathsetmacro\argB{#2}%
\pgfmathsetmacro\argC{#3}%
\expandafter
\endgroup
\expandafter\pgfmathparse\expandafter
{%
\romannumeral`\^^@%
\fpeval{exp(-((ln(\argA)-\argB)^2)/(2*\argC^2))/(\argA*\argC*sqrt(2*pi))}%
}%
}
\begin{tikzpicture}
\begin{axis}[ domain=0.01:10, samples=100 ]
\addplot {lognormal(x,ln(5),0.02)};
\end{axis}
\end{tikzpicture}
\end{document}
它快吗?不快。它有用吗?是的: