pgf:在适合图形的函数中,“维度太大”,/pgf/fpu=true 没有帮助

pgf:在适合图形的函数中,“维度太大”,/pgf/fpu=true 没有帮助

我想绘制对数正态函数:

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

它快吗?不快。它有用吗?是的:

在此处输入图片描述

相关内容