pgfplots:`\tanh` 函数中的奇怪凸起

pgfplots:`\tanh` 函数中的奇怪凸起

后续问题pgfplots:x vs \x


我有一个相当简单的pgfplots图表,但我不明白为什么会有在我的tanh函数中(应该是平滑的)。domain(和samples)键似乎会影响结果。你能解释一下这种行为吗?是否有系统逻辑可以防止这种情况发生(或者我需要使用反复试验的方法)?

\documentclass[tikz,border=1mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest} % Updated after comments, was 1.15 before.

\begin{document}

\begin{tikzpicture}
    \begin{axis}[
        width = 160mm,
        height = 90mm,
        axis lines = center,
        xmin = -10,
        xmax = 10,
        ymin = -1,
        ymax = 1,
        enlarge x limits = 0.05,
        enlarge y limits = 0.10,
        ]
    \addplot[
        color = blue,
        mark = none,
        smooth,
        line width = 1pt,
        domain = -30:30, % When changed to -10:10 then the bump is not visible.
        samples = 200,
        ] {tanh(1*\x)};     
        %       
    \end{axis}
\end{tikzpicture}

\end{document}

在此处输入图片描述

答案1

符号 1 表示他的回答问题的根源。也许缺少的是信息,所有这一切(只)发生在TeX用作计算引擎。由于 Symbol 1 不知道如何修复这个问题(在 TeX 中)(当然这不是冒犯),“修复”是使用另一个计算引擎... ;)

% used PGFPlots v1.18.1
\documentclass[border=5pt]{standalone}
\usepackage{pgfmath-xfp}
    % define `tanh` function
    \pgfmxfpdeclarefunction{Tanh}{1}{1 - 2/(exp(2*#1) + 1)}
\usepackage{pgfplots}
    % use this `compat` level or higher to use Lua as calculation engine
    \pgfplotsset{compat=1.12}
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        domain = 6:7,
        samples = 200,
        no markers,
    ]
        % use TeX as calculation engine
        \addplot {tanh(\x)};
        % use Lua as calculation engine (when compiled with LuaLaTeX of course)
        % (when you compile with pdfLaTeX or use a lower `compat` level than given
        %  in the preamble, this is equivalent to the previous `\addplot`)
        \addplot+ [very thick] {tanh(x)};
        % use xfp as calculation engine
        \addplot+ [thick] {Tanh(x)};
        % use gnuplot as calculation engine
        % (assuming gnuplot is installed, available and it is compiled with
        %  `shell-escape` enabled)
        \addplot gnuplot {tanh(x)};
    \end{axis}
\end{tikzpicture}
\end{document}

该图显示了上述代码的结果

答案2

tanh 定义为 sinh/cosh。而意外的峰值是除法例程中的错误造成的。更准确地说,第 10 行\pgfmathdivide@@中定义的 宏pgfmathfunctions.basic.codegithub 链接) 包含不受欢迎的行为。

\pgfmathdivide@@

此宏使用\pgfmath@x(分子)和\pgfmath@y(分母)来实现长除法。以下是伪代码

While (x > δ & y > δ):
    If x < y:
        append and `0` at the end of \pgfmathresult;
        divide y by 10;
    Else: %%% x ≥ y
        compute a:= floor(x/y);
        If a is single digit:
            append that digit at the end of \pgfmathresult;
            subtract y by x * a
        Else: %%% in this case we always have 10 ≤ a < 20
            subtract a by 10
            depending on how many digits \pgfmathresult has, add 10^-d to \pgfmathresult
            append a to the end of \pgfmathresult

您会发现,当 x/y ≥ 10 时,代码变得很丑陋。通常,您会认为 x/y 总是小于 10,因为前一个 y(除以 10 之前的 y)小于 x,并且将执行个位数分支。因此,这个分支永远不会执行;代码丑陋也没关系。但事实并非如此。

可能出现什么问题?

由于精度有限,可能会发生以下情况

  • (x, y) = (0.00037, 0.00038),因此执行 x < y 分支;y 除以 10。
  • 现在 (x, y) = (0.00037, 0.00003),因此执行 x > y 分支;现在 floor(x/y) = 12 ≥ 10

你可能会说:“好吧。”因为 0.00038 -> 0.00003 只有在 \pgfmathresult已经有多个数字时才会发生,所以添加 0.000012 或 0.00009 并不重要。但有时确实如此。

你看,将 10^-d 加到\pgfmathresult并不是一件容易的事,因为 0.001 + 0.999 包括进位。因此,不是通过文本操作\pgfmathresult,而是通过

  • 转换\pgfmathresult为 TeX 尺寸 ( \pgfmath@xa),
  • 添加1pt, 0.1pt, ..., 或0.00001pt,
  • 然后将 TeX 尺寸转换回文本。

问题是,如果\pgfmathresult是 0.99999,那么将 0.00001pt 添加到 0.99999pt 的结果就是 1pt,而不是 1.00000pt。回想一下,我们处于 a ≥ 10 分支,我们将在新的末尾附加 a - 10。\pgfmathresult因此,如果 a = 12,我们将得到 1.2 作为结果,而不是 1.000002。

使固定

我不知道如何修复这个问题。

相关内容