为什么超过44帧的进度条会出现运算溢出?

为什么超过44帧的进度条会出现运算溢出?

我正在尝试在 Beamer 主题中实现进度条,但当我达到 45 帧时,我收到错误消息

! Arithmetic overflow.
\progressbar@progressbar ...progressbar@tmpcounta 
\divide \progressbar@tmpdi...

这是我的 MWE:

\documentclass{beamer}

\usepackage{tikz}

\makeatletter
\def\progressbar@progressbar{} % the progress bar
\newcount\progressbar@tmpcounta% auxiliary counter
\newcount\progressbar@tmpcountb% auxiliary counter
\newdimen\progressbar@pbht %progressbar height
\newdimen\progressbar@pbwd %progressbar width
\newdimen\progressbar@tmpdim % auxiliary dimension

\progressbar@pbwd=\paperwidth
\progressbar@pbht=1cm

% the progress bar
\def\progressbar@progressbar{%
    
    \progressbar@tmpcounta=\insertframenumber
    \progressbar@tmpcountb=\inserttotalframenumber
    \progressbar@tmpdim=\progressbar@pbwd
    \multiply\progressbar@tmpdim by \progressbar@tmpcounta
    \divide\progressbar@tmpdim by \progressbar@tmpcountb
    
    \begin{tikzpicture}
    \useasboundingbox (0pt, 0pt) rectangle ++ (\progressbar@pbwd, \progressbar@pbht);
    \begin{scope}
    \clip (\progressbar@tmpdim, 0pt) rectangle (\progressbar@pbwd, \progressbar@pbht);
    \node[anchor=south west,inner sep=0pt,outer sep=0pt,minimum height=1cm,minimum width=\paperwidth,fill=green] at (0pt,0pt) {};
    \end{scope}
    \end{tikzpicture}%
}

\addtobeamertemplate{footline}{}{\vspace*{-1cm}\progressbar@progressbar}
\makeatother

\begin{document}
\foreach \x in {1,2,...,45} {\begin{frame}[label=test]{My frame}
    Test \x
\end{frame}}

\end{document}

背后的原因是什么?我该如何避免?

答案1

TeX 有一个\maxdimen( 16383.99999pt),它表示维度表达式中可以使用的最大维度。请参阅\maxdimen此网站上的讨论,包括我的答案

什么时候\x == 45

  • \progressbar@tmpdim == 364.19536pt\progressbar@tmpcounta == 45
  • 它们的乘积364.19536pt * 45 = 16,388.7912pt略大于\maxdimen,因此引发“算术溢出”,乘法结果被截断。

由于最终结果@tmpdim * @tmpcounta / @tmpcountb小于\maxdimen,我们可以先计算@tmpcounta / @tmpcountb,然后计算@tmpdim * <ratio>。下面是使用\pgfmathparsefrom 的尝试pgfmath,它是 的自动加载子包tikz

\documentclass{beamer}

\usepackage{tikz}

\makeatletter
\def\progressbar@progressbar{} % the progress bar
\newcount\progressbar@tmpcounta% auxiliary counter
\newcount\progressbar@tmpcountb% auxiliary counter
\newdimen\progressbar@pbht %progressbar height
\newdimen\progressbar@pbwd %progressbar width
\newdimen\progressbar@tmpdim % auxiliary dimension

\progressbar@pbwd=\paperwidth
\progressbar@pbht=1cm

% the progress bar
\def\progressbar@progressbar{%
    \progressbar@tmpcounta=\insertframenumber
    \progressbar@tmpcountb=\inserttotalframenumber
    \progressbar@tmpdim=\progressbar@pbwd
    % to show current values
    \rlap{\the\progressbar@tmpdim, \the\progressbar@tmpcounta}%
    \pgfmathparse{\progressbar@tmpcounta/\progressbar@tmpcountb}%
    \progressbar@tmpdim=\pgfmathresult\progressbar@tmpdim
    \begin{tikzpicture}
    \useasboundingbox (0pt, 0pt) rectangle ++ (\progressbar@pbwd, \progressbar@pbht);
    \begin{scope}
      \clip (\progressbar@tmpdim, 0pt) rectangle (\progressbar@pbwd, \progressbar@pbht);
      \node[anchor=south west,inner sep=0pt,outer sep=0pt,minimum height=1cm,minimum width=\paperwidth,fill=green] at (0pt,0pt) {};
    \end{scope}
    \end{tikzpicture}%
}

\addtobeamertemplate{footline}{}{\vspace*{-1cm}\progressbar@progressbar}
\makeatother

\begin{document}
\foreach \x in {1,2,...,45} {\begin{frame}[label=test]{My frame}
    Test \x
\end{frame}}

\end{document}

更新

抱歉,昨天太关注“算术溢出”的错误信息了,没注意到绘制进度条的全貌。灵感来自@TobiBS 的回答,我发现实现可以进一步简化为

\documentclass{beamer}
\usepackage{tikz}

\makeatletter
\newdimen\progressbar@height
\progressbar@height=1cm

\addtobeamertemplate{footline}{}{%
  \begin{tikzpicture}
    \useasboundingbox (0pt, 0pt) rectangle (\paperwidth, \progressbar@height);
    % you can use pgfmath expressions directly in coordinate specifications
    \fill[green] (\insertframenumber/\inserttotalframenumber*\paperwidth, 0)
       rectangle (\paperwidth, \progressbar@height);
  \end{tikzpicture}%
}
\makeatother

\begin{document}
\foreach \x in {1,2,...,50} {
  \begin{frame}{My frame}
    Test \x
  \end{frame}
}
\end{document}

答案2

我现在使用的更简化的方法可能更容易阅读,但当然不像以前那么灵活,但它利用了这样一个事实:对于 PGF,您不需要将宏转换为计数器,因此这可以生成高度可变且倒置的进度条。它还考虑了 muzimuzhi 关于使用的评论\pgfmathsetmacro

\documentclass{beamer}

\usepackage{tikz}

\makeatletter
\newdimen\progressbar@height
\newcount\progressbar@progress
\progressbar@height=1cm

\addtobeamertemplate{footline}{}{%
\begin{tikzpicture}
\useasboundingbox (0pt, 0pt) rectangle ++ (\paperwidth, \progressbar@height);
\begin{scope}
\pgfmathsetmacro\progressbar@progress{\insertframenumber/\inserttotalframenumber}
\clip (\progressbar@progress * \paperwidth, 0pt) rectangle (\paperwidth, \progressbar@height);
\node[anchor=south west,inner sep=0pt,outer sep=0pt,minimum height=1cm,minimum width=\paperwidth,fill=green] at (0pt,0pt) {};
\end{scope}
\end{tikzpicture}%
}
\makeatother

\begin{document}
    \foreach \x in {1,2,...,50} {\begin{frame}{My frame}
        Test \x
\end{frame}}

\end{document}

相关内容