8

Background:

I am stuck on a "Dimension too large" problem which is occurring during index generation. This is a large index of links to files (along with other related information), and am sure the problem is not with the indexing packages, but in my code that adds the related information. The message I get in my actual use case is:

./FileName-FileName.ind:8741: Dimension too large. \pgfmath@x

l.8741 ...path to file} \hyperpage{119} ?

If I reduce the size of this index (even if it includes the offending file that was being linked to, as listed in the error message above) the problem does not occur. So, it is not a problem with the file listed in the error message, but with the macros that determine which related information to add.

If I could get a stack dump and know what part of my code calls pgfmath before the problem occurs, then I could have some hope of determining the root of the problem. This same code is executed 1000s of times before the problem shows up, so I can't just terminate early by putting an undefined macro in the code to do a manual trace.


Sample Test Case

Although things are obvious in the "cooked" up MWE below, they are not in my actual code. The MWE below terminates with:

./TeX-SE.tex:38: Dimension too large.
to be read again
\relax l.38 }
%

So, from the error message I know where the problem originates in the main source code. But form there, how do I determine where the problem lies? Also note that the error message here gives no indication that the problem is some pgfmath function.

References:

Notes:

  • In the MWE below, the source of the problem is obvious and several fixes are possible. But, in my actual use case I have not yet been able to narrow down the source of a problem with a similar error message. So, this question is about how do I narrow down the source of the problem, not how do I fix this specific issue..

Code:

\begin{filecontents*}{GrillFunctions.sty}
    \newcommand*{\FunctionValue}[1]{%
        % ... lots of code ....
        \pgfmathsetmacro{\NewValue}{\arabic{MyCounter}/100}%
        \num{\NewValue}%
        % ... lots of code ....
    }
\end{filecontents*}

\begin{filecontents*}{GrillMacros.sty}
    \newcommand*{\DeterminePercentage}[1]{%
        % ... lots of code ....
        % ... Don't know what in here is creating the problem.
        %     Obvious given this MWE, but in actual usage not so obvious
        \FunctionValue{#1}%
        % ... lots of code ....
    }
\end{filecontents*}


\documentclass[12pt]{article}
\usepackage{siunitx}
\usepackage{xstring}
\usepackage{tikz}
\usepackage{GrillFunctions}
\usepackage{GrillMacros}

\newcounter{MyCounter}
\setcounter{MyCounter}{100000}


\begin{document}
\IfStrEq{\arabic{MyCounter}}{0}{%
    Value of counter is zero.%
}{%
    Value of counter is \DeterminePercentage{\arabic{MyCounter}}.%
}%
\end{document}
13
  • TeX is a macro expansion language: there is no stack trace to see. That's why building MWEs and using \tracingall/'marker' macros is so important in debugging TeX code. As such, perhaps all we will be able to say is that you'll have to try to isolate the conditions for the error (not an answer, clearly!).
    – Joseph Wright
    Commented Aug 5, 2014 at 6:19
  • @JosephWright: Is there a good question on here that explains where \tracingall gets its information from? If one could access that, then it should be possible to build a stack trace. Or perhaps I can conditionally enable \tracingall after a certain number of iterations. I will try that... Commented Aug 5, 2014 at 6:33
  • \tracingall isn't a primitive it just sets all of texs tracing registers to their maximum values you also don't need tracingall (eg trace the paragraph breaker, probably just \tracingmacros=2 Commented Aug 5, 2014 at 6:41
  • @DavidCarlisle: When I add \tracingmacros=2 to the MWE, I don't see how to read that to find the problem. Even knowing that the problem is with \FunctionValue in this case and searching for it in the log file, we see that \FunctionValue shows up only on the lines around 870 in the log file, but there are over 2000 lines in the log file. Commented Aug 5, 2014 at 6:49
  • 3
    Small correction to Andrew's comment: TeX dimensions are limited to 16383.99998pt, but TeX integers are limited to 2147483647. Commented Aug 5, 2014 at 7:49

4 Answers 4

8

So if I was debugging this I'd add tracing so the MWE looked like

\begin{document}
\tracingmacros2
\tracingassigns2

Then run the MWE stopping at the error:

! Dimension too large.
<to be read again> 
                   \relax 
l.39 }
      %
? x
No pages of output.

then look at the log file in an editor, starting from the error:

#1<-\pgfmath@operand@b 
#2<-\pgfmath@operand@a 

\pgfmath@operand@b ->100000

! Dimension too large.
<to be read again> 
                   \relax 
l.39 }

so we know \pgfmath@operand@b being the first argument to the last macro expanded ended up being 100000 which is too large in this context. So interesting thing is where that value of 100000 came from. So simplest thing rather than trying to trace the full expansion logic is to just search backwards for 100000

It crops up in various places eg

{changing \pgfmath@stack@operand@top=macro:->100000}

but in that case it had come from

#1<-100000

ie it was the first argument to that macro, so work back to see where it came from...

\pgfmathresult ->100000

looks promising....

but keep going

#1<-100000/100

bit of a clue it was trying to work out a percentage...

\@arabic #1->\number #1
#1<-\c@MyCounter 
{changing \@xs@arg@i=\relax}
{into \@xs@arg@i=\long macro:->100000}

Hmm the 100000 is the arabic value of MyCounter and there is no earlier occurrence of 100000 (because I started tracing after begin{document} I could have started tracing at the \setcounter{MyCounter}{100000} but that would be cheating:-)

So basically the log tells you that the LaTeX counter MyCounter was used in a calculation at a point that it had the value 100000 which is too large. At that point either you recognise where you are and what to change or you move the tracing back (and perhaps turn on \tracingifs or some of the other trace options and see how and why MyCounter got that value...

So although the log had 2500 lines, it's quite readable if you read it backwards and only read half a dozen of the lines:-)

9

TeX is a macro expansion language and as such there is no stack trace: when a macro \foo is expanded to it's replacement text, the fact that this came from one macro rather than another or just by being part of the source directly is not recorded. Debugging TeX issues therefore requires a different approach using the tools TeX does provide.

Probably the most common approach to finding issues it to use the macro \tracingall, which is available in plain TeX, LaTeX and ConTeXt. After \tracingall a number of registers are set which lead to TeX printing additional information in the log file. As noted in comments, the primitive setting \tracingmacros=2\relax, which is part of \tracingall, is probably the single most useful setting to employ in tracing an issue due to macro expansion. Adding either \tracingall or \tracingmacros=2\relax will potentially lead to a very long log file, which then needs to be read through by hand. As you are looking for an error, it's probably easiest to do this by searching for the error line then reading backward to see what was happening to cause it.

With more complex situations such as this one, other techniques are also helpful. One is the 'classic' of forcing TeX to pause the run by inserting some undefined control sequence (e.g. \ERROR) part-way though the source. This can help to pin down where an issue is occurring and so reduce how much tracing is needed.

With a loop situation, it's potentially useful to add some code to the loop to for example print register values to the log (e.g. \immediate\write-1{Value is: \the\RegisterOfInterest}) or to start tracing only when some condition is met (e.g. \ifnum\mycount>1000 \expandafter\tracingall\fi).

Beyond these 'standard' techniques, it usually comes down to carefully modifying the source and definitions it uses to 'pull out' the important information, then perhaps constructing some test cases and working through systematically.


Taking the example in the question, if I apply \tracingmacros just before \IfStrEq and turn it off after the conditional, I get a log of 14449 lines with the error on line 2066. The relevant lines just before the error read:

\pgfmathdivide@ #1#2->\begingroup \pgfmath@x =#1pt\relax \pgfmath@y =#2pt\relax
 \let \pgfmath@sign =\pgfmath@empty \ifdim 0pt=\pgfmath@y \pgfmath@error {You'v
e asked me to divide `#1' by `#2', but I cannot divide any number by `#2'}\fi \
afterassignment \pgfmath@xa \c@pgfmath@counta \the \pgfmath@y \relax \ifdim 0pt
=\pgfmath@xa \divide \pgfmath@x by\c@pgfmath@counta \else \ifdim 0pt>\pgfmath@x
 \def \pgfmath@sign {-}\pgfmath@x =-\pgfmath@x \fi \ifdim 0pt>\pgfmath@y \expan
dafter \def \expandafter \pgfmath@sign \expandafter {\pgfmath@sign -}\pgfmath@y
 =-\pgfmath@y \fi \ifdim 1pt>\pgfmath@y \pgfmathreciprocal@ {\pgfmath@tonumber
{\pgfmath@y }}\pgfmath@x =\pgfmath@sign \pgfmathresult \pgfmath@x \else \def \p
gfmathresult {0}\pgfmath@divide@periodtrue \c@pgfmath@counta =0\relax \pgfmathd
ivide@@ \pgfmath@x =\pgfmath@sign \pgfmathresult pt\relax \fi \fi \pgfmath@retu
rnone \pgfmath@x \endgroup
#1<-\pgfmath@operand@b
#2<-\pgfmath@operand@a

\pgfmath@operand@b ->100000

! Dimension too large.
<to be read again>
                   \relax
l.39 }
      %
?

What we see here is that TeX expands \pgfmathdivide@ to that rather long definition with \pgfmath@operand@b as #1 and \pgfmath@operand@b as #2. TeX now works through the tokens: it begins a group (which doesn't show up in this trace: I'll come back to that), then comes to

\pgfmath@x =#1pt\relax

which is a primitive register assignment. That requires #1 expands, so we see in the log \pgfmath@operand@b ->100000 (remember #1 is \pgfmath@operand@b). That then causes the error as the value is too big to assign to a register (the limit for a dimen is 16383.99998pt, and as pt are used as the unit here 100000 is too big).

If I'd also set \tracingcommands=2\relax I get a much longer log but a bit more info here:

\pgfmathdivide@ #1#2->\begingroup \pgfmath@x =#1pt\relax \pgfmath@y =#2pt\relax
 \let \pgfmath@sign =\pgfmath@empty \ifdim 0pt=\pgfmath@y \pgfmath@error {You'v
e asked me to divide `#1' by `#2', but I cannot divide any number by `#2'}\fi \
afterassignment \pgfmath@xa \c@pgfmath@counta \the \pgfmath@y \relax \ifdim 0pt
=\pgfmath@xa \divide \pgfmath@x by\c@pgfmath@counta \else \ifdim 0pt>\pgfmath@x
 \def \pgfmath@sign {-}\pgfmath@x =-\pgfmath@x \fi \ifdim 0pt>\pgfmath@y \expan
dafter \def \expandafter \pgfmath@sign \expandafter {\pgfmath@sign -}\pgfmath@y
 =-\pgfmath@y \fi \ifdim 1pt>\pgfmath@y \pgfmathreciprocal@ {\pgfmath@tonumber
{\pgfmath@y }}\pgfmath@x =\pgfmath@sign \pgfmathresult \pgfmath@x \else \def \p
gfmathresult {0}\pgfmath@divide@periodtrue \c@pgfmath@counta =0\relax \pgfmathd
ivide@@ \pgfmath@x =\pgfmath@sign \pgfmathresult pt\relax \fi \fi \pgfmath@retu
rnone \pgfmath@x \endgroup
#1<-\pgfmath@operand@b
#2<-\pgfmath@operand@a
{\begingroup}
{\dimen153}

\pgfmath@operand@b ->100000

! Dimension too large.
<to be read again>
                   \relax
l.40 }
      %
?

Notice that with command tracing TeX shows me that \begingroup being executed and also the fact it's trying to assign a register, which happens to be \dimen153 in this case (you can check earlier in the log that \pgfmath@x is \dimen153).

What you'll find in this example is that as pgf does lots of work you get a very long log: use a proper tool to view it (something like less or a 'programmers editor', not something that tries to load all of the file into memory in one go).

3
  • Thanks, that is useful info. What is the difference between \immediate\write-1 and \typeout{}? Commented Aug 5, 2014 at 7:44
  • \typeout{foobar} writes foobar to the log and terminal, while \immediate\write-1{foobar} writes foobar to the log only. Commented Aug 5, 2014 at 7:52
  • @PeterGrill In addition to what Bruno says, \typeout is a LaTeX macro and so deals with LaTeX2e's 'protected' stuff, but it's not available with other formats. For debugging I often end up using plain or multiple formats, so using primitives tends to be handy.
    – Joseph Wright
    Commented Aug 5, 2014 at 7:53
5

The following explains and removes the problem of the test case. It's intended for people stumbling over the specific problem, but it's not an answer for the general case of debugging.

The mathematical engine of pgf sees values without units as pt values. Therefore, you used 100000pt implicitly which caused the error. If you use a unit deliberatley (in my answer sp), the problem can be circumvented. My code gives 100 as result which you may have intended (?). Your code would have given 1000 if things would have worked. If this was really your intention, replace 65.536 by 655.36 in the code below.

\RequirePackage{filecontents}
\begin{filecontents*}{GrillFunctions.sty}
    \newcommand*{\FunctionValue}[1]{%
        % ... lots of code ....
        \pgfmathsetmacro{\NewValue}{\arabic{MyCounter}sp*65.536}% <----------
        \num[round-mode=places,round-precision=2]{\NewValue}%
        % ... lots of code ....
    }
\end{filecontents*}

\begin{filecontents*}{GrillMacros.sty}
    \newcommand*{\DeterminePercentage}[1]{%
        % ... lots of code ....
        % ... Don't know what in here is creating the problem.
        %     Obvious given this MWE, but in actual usage not so obvious
        \FunctionValue{#1}%
        % ... lots of code ....
    }
\end{filecontents*}


\documentclass[12pt]{article}
\usepackage{siunitx}
\usepackage{xstring}
\usepackage{tikz}
\usepackage{GrillFunctions}
\usepackage{GrillMacros}

\newcounter{MyCounter}
\setcounter{MyCounter}{100000}


\begin{document}
\IfStrEq{\arabic{MyCounter}}{0}{%
    Value of counter is zero.%
}{%
    Value of counter is \DeterminePercentage{\arabic{MyCounter}}.%
}%
\end{document}
4
  • Thanks, as that is definitely a good suggestion, but that wasn't what I had intended with the question. I want to know where is the root of the problem in my actual code. From the MWE it is obvious where the problem is, so a fix can be applied. But in my actual use case, I don't know where the source of the problem is -- hence the request for debugging advice to obtain something like a stack trace. Commented Aug 5, 2014 at 6:14
  • @PeterGrill I would insert some \show\whatever commands at critical points of the code to encircle the problem. That's the way I find the the problematic place for most cases. It's a poor mans debugging but it works quite well. Commented Aug 5, 2014 at 6:18
  • Yeah, I am more than willing to use such techniques, but in this case the problem only occurs after many thousand successful execution of the same code. So problem with any such break points, is that I don't know if I am yet at the spot where the problem is. If I could narrow down the source of the problem, than such techniques would be useful. Commented Aug 5, 2014 at 6:22
  • @PeterGrill I see. If you do have a counter or something in the repetition, maybe a conditional \show does help (if the counter value is greater than something). But I know, it's clumsy and annoying to track down an error with that ... Commented Aug 5, 2014 at 6:36
3

Counters are, as you can see, also limited for such computations that involve borderline numbers for TeX. Preferably switch to fpu library, then you won't have any problems up to 2^324. And beyond that you should use proper tools not TeX anyway :) Here is a pretty big number handled by fpu. Recent L3 math can also cope with these if I remember correctly.

\documentclass[12pt]{article}
\usepackage{xstring,tikz}
\usetikzlibrary{fpu}

\def\FunctionValue#1{%
        \pgfkeys{/pgf/fpu}%
        \pgfmathsetmacro{\NewValue}{#1/100}%
        \pgfmathprintnumber[fixed,1000 sep={}]{\NewValue}%
        \pgfkeys{/pgf/fpu=false}%
    }
\def\DeterminePercentage#1{\FunctionValue{#1}}
\def\myval{100000000000000000000000000000000000000}

\begin{document}
    Value of counter is \DeterminePercentage{\myval}.%
\end{document}
8
  • The L3 FPU is IEEE754-compliant, so has no issues here provided floats are appropriate. 'Big integer' and 'big float' calcs are both doable in TeX, but as you say not necessarily recommended!
    – Joseph Wright
    Commented Aug 5, 2014 at 10:30
  • @JosephWright I meant you can't set a counter that high. But yes, I think we should promote L3 fpu better as opposed to pgfmath since it is optionally uses fpu libraries and it is not compatible with the drawing engine.
    – percusse
    Commented Aug 5, 2014 at 10:35
  • @percusse: Yep, already tried that before posting question, and problem still occurred. So, must be some other arithmetic issue... Wait.. I did not try setting \pgfkeys{/pgf/fpu}. I thought \usetikzlibrary{fpu} was sufficient. Will try \pgfkeys{/pgf/fpu}. Commented Aug 5, 2014 at 19:41
  • With \def\myval{123456789} I get Value of counter is 1234560 which seems to be weird.
    – user4686
    Commented Sep 27, 2014 at 19:24
  • @jfbu Indeed. This happens when relatively distant (in terms of exponents) numbers are used. Main reason is that fpu convert everything to mantissa-exponent form and details are lost in the mantissa. There are a few tricks but it's not-so-nice.
    – percusse
    Commented Sep 28, 2014 at 10:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .