后续问题看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.code
(github 链接) 包含不受欢迎的行为。
\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。
使固定
我不知道如何修复这个问题。