使用 addplot 时,`\ifnum 中缺少 = 插入`

使用 addplot 时,`\ifnum 中缺少 = 插入`

我正在尝试策划一个归一化 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不再可用10无法\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

相关内容