我正在尝试策划一个归一化 sinc 函数使用 PGFPlots/TikZ。由于极限值为 0,这有点棘手,我使用了percusse 提供的建议。
sincf
这是一个最小的例子(请注意,由于与文档的其余部分冲突,我已将该函数重命名为,并插入了 Pi 的近似值以进行规范化):
\documentclass{scrreprt}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}
\begin{document}
\begin{tikzpicture}
% https://tex.stackexchange.com/a/235009
\pgfmathdeclarefunction{sincf}{1}{%
\pgfmathparse{abs(#1)<0.01 ? int(1) : int(0)}%
\ifnum\pgfmathresult>0 %
\pgfmathparse{1}%
\else%
\pgfmathparse{sin(3.14159*#1 r)/(3.14159*#1)}%
\fi%
}
\begin{axis}
\addplot {sincf(\x)};
\end{axis}
\end{tikzpicture}
\end{document}
但是,我收到了两个我无法弄清楚的错误:
! Missing = inserted for \ifnum.
<to be read again>
Y
l.23 \addplot plot (\x,{sincf(\x)});
I was expecting to see `<', `=', or `>'. Didn't.
! Missing number, treated as zero.
<to be read again>
Y
l.23 \addplot plot (\x,{sincf(\x)});
A number should have been here; I inserted `0'.
(If you can't figure out why I needed to see a number,
look up `weird error' in the index to The TeXbook.)
使用 MikTeX 2.9
答案1
pgfplots
默认情况下使用库fpu
来提高精度,该库具有不同的内部数字格式。因此\pgfresult
不再可用1
,0
无法\ifnum
使用。
\tikzset{fpu}
\pgfmathparse{int(0)}\show\pgfmathresult
\pgfmathparse{int(1)}\show\pgfmathresult
这些线表示0Y0
零和1Y1
一。
在这种情况下,整个数学运算可以用一个\pgfmathparse
表达式来表达:
\documentclass{scrreprt}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}
\begin{document}
\begin{tikzpicture}
% http://tex.stackexchange.com/a/235009
\pgfmathdeclarefunction{sincf}{1}{%
\pgfmathparse{(abs(#1)<0.01) ? 1 : sin(pi*#1 r)/(pi*#1)}%
}
\begin{axis}
\addplot {sincf(\x)};
\end{axis}
\end{tikzpicture}
\end{document}
答案2
不幸的是,现有的两个答案都有缺点。
Heiko Oberdiek 的回答:它确实撤消了链接问题中的修复。在这种情况下,\addplot
恰好没有在 处评估函数x=0
,但如果它这样做了……
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17}
\begin{document}
\pgfmathdeclarefunction{sincf}{1}{%
\pgfmathparse{(abs(#1)<0.01) ? 1 : sin(pi*#1 r)/(pi*#1)}%
}
\pgfmathparse{sincf(0)}
\end{document}
你收到错误。
Cryptc 的答案有效,但前提是 FPU 当前已启用并且输出格式为浮点数。
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17}
\begin{document}
\pgfkeys{/pgf/fpu=true,/pgf/fpu/output format=fixed}
\pgfmathparse{1} % stores 1.0000000000 to \pgfmathresult
\pgfmathfloattofixed{\pgfmathresult} % \pgfmathfloattofixed, as with other \pgfmathfloat... functions, expect input in low-level PGF FPU representation
\end{document}
错误。
我发现将任何东西转换为 int 的一种方法是通过 PGF 的 FPU 往返:
\documentclass{article}
\usepackage{tikz}
% don't need fpu library!
\begin{document}
% works with both internal representation and "normal" representation
\pgfmathfloatparsenumber{1Y1.0e6]}
\pgfmathfloattoint\pgfmathresult
% now \pgfmathresult is always an integer
\pgfmathfloatparsenumber{1000000}
\pgfmathfloattoint\pgfmathresult
\end{document}
你可以尝试\pgfmathtruncatemacro
,但是如果启用了 FPU 并且输出格式为浮点数,这将默默返回错误的错误!
因此,对于这个问题,解决方法是
\documentclass{scrreprt}
\usepackage{pgfplots}
\pgfplotsset{compat=1.12}
\begin{document}
\pgfmathdeclarefunction{sinc}{1}{%
\pgfmathparse{abs(#1)<0.01 ? 1 : 0}%
% ======== add these 2 lines ========
\pgfmathfloatparsenumber\pgfmathresult
\pgfmathfloattoint\pgfmathresult
% ======== end ========
\ifnum\pgfmathresult>0 %
\pgfmathparse{1}%
\else%
\pgfmathparse{sin(3.14159*#1 r)/(3.14159*#1)}%
\fi%
}
\begin{tikzpicture}
\begin{axis}
\addplot {sinc(\x)};
\end{axis}
\end{tikzpicture}
% ======== double check it works with normal \draw plot
\begin{tikzpicture}
\draw (-1,0) -- (1,0);
\draw[domain=0:0.5, samples=250] plot (\x,{sinc(20*\x)});
\end{tikzpicture}
\end{document}
与 TikZ\draw plot
和都兼容\addplot
。
或者,完全保留在FPU内,有\pgfmathfloatifflags
:
\pgfmathdeclarefunction{sinc}{1}{%
\pgfmathparse{abs(#1)<0.01}%
\pgfmathfloatparsenumber\pgfmathresult
\pgfmathfloatifflags{\pgfmathresult}{1}{% "less than" is true
\pgfmathparse{1}%
}{% "less than" is false
\pgfmathparse{sin(3.14159*#1 r)/(3.14159*#1)}%
}%
}
也快一点。
另一种选择,尽管具体到这个问题,是
\pgfmathdeclarefunction{sinc}{1}{%
\pgfmathparse{(#1==0 ? 1: sin(3.14159*#1 r))/(#1==0 ? 1: 3.14159*#1)}%
}
(只要盯着代码一会儿你就会明白它为什么有效。)
我试图制造ifthenelse
短路,但解析时立即求值行为与的行为根深蒂固\pgfmathparse
,因此似乎很难修复。
答案3
使用相关的回答关于浮点运算单元格式化,\ifnum
如果我的结果在int() 的范围[−16383.9998, +16383.9998]。诀窍是\pgfmathfloattofixed
在 上使用\pgfmathresult
。
\pgfkeys{/pgf/fpu=true}
\pgfmathparse{...do floating point math here (with an int() result)...}
\pgfmathfloattofixed{\pgfmathresult} % this allows the conversion with int()
\edef\tmp{\pgfmathresult}
\pgfkeys{/pgf/fpu=false}
\pgfmathsetmacro\iTmp{int(\tmp)} % convert with int()
\ifnum \iTmp>0
... do stuff ...
\fi