4

I am trying to implement a progress bar into my beamer theme, but as soon as I hit 45 frames, I get the error message

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

Here is my 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}

What is the reason behind and how can I avoid it?

6

TeX has a \maxdimen (16383.99999pt), which represents the largest dimension you can use in an dimension expression. See discussions among \maxdimen on this site, including my answer.

When \x == 45,

  • \progressbar@tmpdim == 364.19536pt and \progressbar@tmpcounta == 45,
  • their multiplication 364.19536pt * 45 = 16,388.7912pt, is slightly larger than \maxdimen, hence raises "arithmetic overflow" and the result of multiplication is truncated.

Since the final result @tmpdim * @tmpcounta / @tmpcountb is smaller than \maxdimen, we can firstly compute @tmpcounta / @tmpcountb, then compute @tmpdim * <ratio>. Here is a try making use of \pgfmathparse from pgfmath, which is an autoloaded sub-package of 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}

Update

Sorry, I paid too much attention to the error message "arithmetic overflow" yesterday, but not the whole picture of drawing a progress bar. Inspired by @TobiBS's answer, I find the implementation can be further simplified to

\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}
6
  • Thanks @muzimuzhiZ, actually using \pgfmathparse enabled me to simplify the calculation even further, I now directly refer to the page number macros from beamer without the overhead of two more counters. If you are OK, I would add it to your answer.
    – TobiBS
    Jul 22 '20 at 7:35
  • @TobiBS I'm OK. You can add it to my answer, or add a new answer directly. Jul 22 '20 at 17:48
  • actually I now simplified so much, because I copied the original code from an example and don't need to have so many sizes configurable, that it doesn't make sense to edit your answer, because I'd have to modify my question then, as well. The simplification is mainly to directly use \pgfmathresult in the node: \pgfmathparse{\insertframenumber/\inserttotalframenumber} \clip (\pgfmathresult * \paperwidth, 0pt) rectangle (\paperwidth, \progressbar@pbht);
    – TobiBS
    Jul 22 '20 at 18:02
  • @TobiBS You can append a further simplified version to my answer or post that in a new answer. And, since the value of \pgfmathresult might be overwritten in tikz drawing commands, using \pgfmathsetmacro to store result in a separate macro is more safe. Jul 22 '20 at 18:58
  • I did so and would like to get your comment on the solution, if there is anything that should be avoided or improved, feel free to edit and let me know.
    – TobiBS
    Jul 22 '20 at 19:12
0

A more simplified approach that I am now using might be a bit easier to read, but of course not as flexible as before, but it makes use of the fact that for PGF you don't need to convert the macros to counters before, hence this works to produce a progress bar that is variable in height and is inverted. It also takes into account muzimuzhi's comment regarding the use of \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}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.