As diagnosed by David Carlisle, the culprit is graphics
's \Gscale@div
. Indeed notice that the employed algorithm may create overflows, a typical example being with 8192
divided by 0.75
(in theory, it should be allowed to divide it by as small as 0.5+epsilon
, to obey the <16384
constraint on the result from \maxdimen=16384pt-1sp
, taking as premise that the final result itself is produced via \the
applied to a dimen register)
This answer has now four parts A, B, C, D displayed in order C+D, B, A.
A: original answer which defines a one-liner replacement of \Gscale@div
for dividing two lengths, using e-TeX (and skipping some checks done by original \Gscale@div
). I know there is a similar expression elsewhere on this site, which I have hit against recently I recall it was in some post from 2011 or 2012.
B: a replacement of \Gscale@div
which does not use e-TeX facilities and is written using the usual scratch macros and registers of LaTeX. The computation is guaranteed not to create overflow if the (rounded) result is at most 16384 - 2/65536
. As discussed below, when the divisor is at most 0.5pt
a truncation, but when it is at least 0.5pt
a rounding of the exact ratio is done to an integer multiple of sp
unit (=1/65536
). For people wanting rounding in all cases for coherence, see part D.
C: here on top, a \divdef
macro for dividing two TeX dimensions, with no restriction whatsoever on the size of the result. Initially I wrote it starting from B and with dividing counts in mind, but as the result is a fixed point decimal with up to five digits after the mark, and as the only way to use this as input in TeX (natively, with no extra lines of code) is to consider it as a dimension (in pt, usually), in the end I again assumed the inputs to be dimension resgisters or specifications (the \setlength
part is dropped --- and its overhead when calc
package is used --- as this is written for being usable in Plain too.) This can be used directly in Plain TeX. The \divdef
macro is a very small variant of the \Gscale@div
or part B, which exploits the fact that the latter separates the integer part from the decimal part (but some pieces of the code use operations on counts where \Gscale@div
of Part B uses dimensions). I hesitated about again using \the
on a dimension to do the final conversion to decimal writing, because it could be handled otherwise, but then one would have to worry about recovering the same rounding exactly as TeX would do via \the
. The ratio R
is computed as the nearest integral multiple of 1/65536
(ties go to even; but see next item for more precise description) and then (its fractional part is) converted to a decimal number via TeX's \the
.
D: actually the code in C and B has two branches; the above description about rounding applies when the divisor is >0.5pt
. For a divisor at most 0.5pt
the fraction is truncated, not rounded, to nearest multiple of 1/65536
, before conversion to decimal expansion via \the
. Thus in part D, the code is modified to always do the rounding, with ties go to even. I hesitated about this because TeX
's \divide
truncates rather than rounds. On the other hand e-TeX
's /
operator (which allows only integral divisors, by the way) rounds (which is a cause of annoyance sometimes), but it rounds away from zero, not obeying the "ties go to even" rule.
Note 1: naturally the 4 or 5 decimal digits are illusory precision when the integer part is large, in the sense that the dimensions we divide may have already incorporated roundings of a much lesser precision. But it is the mathematically precise result of evaluating the ratio of the integers which internally code the two dimensions as integral multiples of sp unit.
Note 2: as the result may (largely!) exceed \maxdimen
as a multiple of pt
unit, the code in C and D should set a flag to tell when this is the case, so that subsequent routines can make decisions based on that.
Part C+D. "divide two dimensions and output a fixed point number (with at most 4 or 5 decimals after the mark)" macro, with no condition whatsoever on the size (does not use e-TeX, written for Plain)
The image below illustrate division with a small divisor, hence truncation is done as explained above. Notice that for comparison if one does
\dimen@ 3pt
\divide\dimen@ by 10
\the\dimen@
TeX prints 0.29999pt
, which is coherent with what one observes below for example in case of division of \maxdimen
by 10
. This is due to the fact that the code below truncates the exact ratio when the divisor is small (at most than 0.5pt
).

But here is now the same thing when using Part D code which rounds in all cases:
(observe the differences)

In both cases an interesting issue is illustrated by 1073741823/37
. If we go straight to decimal expansion (without the intermediate rounding/truncating to an integer multiple of 1/65536
) the correct fractional part is .27027...
(and is barely bigger). But because of the intermediate step either as in Part C or in Part D code, we end up with .27026
as fractional part.
Code for Part C:
% plain TeX, mais j'ai besoin de \loop à la LaTeX
\catcode`\@ 11
\countdef\ddf@cnta=\z@
\countdef\ddf@cntb=\tw@
\countdef\ddf@cntc=4
\countdef\ddf@cntd=6
% LaTeX loop or any loop allowing \else\repeat:
\long\def\loop #1\repeat{%
\def \iterate {#1\relax \expandafter \iterate \fi}\iterate
\let \iterate \relax }
\def\divdef #1#2#3{%
% description:
% computes R = #2/#3 as nearest multiple of 1/65536 (ties go to even)
% then define the macro #1 to be the decimal expansion of this up to five digits
% after decimal mark the last job being made by TeX's \the.
% the computation is guaranteed overflow free (it is not
% checked if #3 = 0). But there is not much one can do with the
% raw output if it exceeds `\maxdimen`. Notice that trailing zeroes
% of the fractional part are suppressed, and if nothing remains,
% the result put into #1 has no decimal mark either.
% note: if #3<32768sp=0.5pt, the ratio R is not rounded, but truncated
% to nearest integer multiple of 1/65536 (before decimal conversion).
\begingroup
\dimen@ #3\relax % denominator
\dimen@ii #2\relax % numerator
\ifdim\dimen@<\z@
\dimen@-\dimen@
\dimen@ii-\dimen@ii
\fi
\ifdim\dimen@ii<\z@
\def\ddf@sgn{-}\dimen@ii-\dimen@ii
\else
\let\ddf@sgn\empty % no \@empty in Plain !
\fi
\ddf@cnta\dimen@ % non negative denominator (we hope non zero...)
\ddf@cntb\dimen@ii % non negative numerator
\divide\ddf@cntb\ddf@cnta % integer part of ratio, will be stored in \ddf@cntd
\ddf@cntd\ddf@cntb
\multiply\ddf@cntb-\ddf@cnta % no overflow possible because TeX's division truncates
\advance\ddf@cntb\dimen@ii % now numerator in \ddf@cntb is < denom
\count@\z@ % will store fractional part as a multiple of sp's
\ifnum\ddf@cntb>\z@
\ifnum\ddf@cnta>32768\relax
\ddf@cnta65536\relax
\loop
\ddf@cntc\dimen@ % denominator
\advance\ddf@cntc-\ddf@cntb
\ifnum\ddf@cntb<\ddf@cntc
\divide\ddf@cnta\tw@
\advance\ddf@cntb\ddf@cntb
\else
\ifnum\ddf@cntb=\ddf@cntc
\divide\ddf@cnta\tw@
\advance\count@\ddf@cnta
\ddf@cnta\z@ % abort the loop here
\else
\advance\count@\ddf@cnta % not same order as in previous branch!
\divide\ddf@cnta\tw@
\ddf@cnta-\ddf@cnta
\advance\ddf@cntc\ddf@cntc
\ddf@cntb\ddf@cntc
\fi
\fi
\ifnum\ddf@cnta=\z@\else % signed quantity: can not do if foo>\z@ ...
\repeat
% it is possible here that \count@ is 65536
\else
% here denom <= 2^15=32768 (=0.5pt), hence 65536num < 2^31
\multiply\ddf@cntb65536\relax
\divide\ddf@cntb\ddf@cnta
\count@\ddf@cntb % at most 65535 because division truncates
\fi
\fi
\dimen@\count@ sp\relax
\expandafter\divdef@end\the\dimen@ #1%
}
\begingroup
\catcode`P 12
\catcode`T 12
\lowercase{\gdef\divdef@end #1.#2PT}#3{%
\advance\ddf@cntd #1\relax % almost always #1=0
\ifnum#2>\z@
\edef\x{\endgroup\edef\noexpand#3{\ddf@sgn\the\ddf@cntd.#2}}%
\else
\ddf@cntd\ddf@sgn\ddf@cntd
\edef\x{\endgroup\edef\noexpand#3{\the\ddf@cntd}}%
\fi
\x
}\endgroup
\input xinttools.sty
\def\TAB{&}\def\CR{\cr}
\tabskip 20pt
\halign {#\hfil &#\hfil \cr
\xintFor* #1 in {\xintSeq {1}{50}}\do
{\divdef\x \maxdimen{#1sp}\number\maxdimen/#1=\x
\ifodd #1 \TAB\else\expandafter\CR\fi
}}
% test
% \dimen@ 3pt
% \divide\dimen@ by 10
% \the\dimen@
\bye
Code for Part D (it differs only in the lines in the denom <= 2^15=32768
branch):
\catcode`\@ 11
\countdef\ddf@cnta=\z@
\countdef\ddf@cntb=\tw@
\countdef\ddf@cntc=4
\countdef\ddf@cntd=6
% LaTeX loop or any loop allowing \else\repeat:
\long\def\loop #1\repeat{%
\def \iterate {#1\relax \expandafter \iterate \fi}\iterate
\let \iterate \relax }
\def\divdef #1#2#3{%
% description:
% computes R = #2/#3 as nearest multiple of 1/65536 (ties go to even)
% then define the macro #1 to be the decimal expansion of this up to five digits
% after decimal mark the last job being made by TeX's \the.
\begingroup
\dimen@ #3\relax % denominator
\dimen@ii #2\relax % numerator
\ifdim\dimen@<\z@
\dimen@-\dimen@
\dimen@ii-\dimen@ii
\fi
\ifdim\dimen@ii<\z@
\def\ddf@sgn{-}\dimen@ii-\dimen@ii
\else
\let\ddf@sgn\empty % no \@empty in Plain !
\fi
\ddf@cnta\dimen@ % non negative denominator (we hope non zero...)
\ddf@cntb\dimen@ii % non negative numerator
\divide\ddf@cntb\ddf@cnta % integer part of ratio, will be stored in \ddf@cntd
\ddf@cntd\ddf@cntb
\multiply\ddf@cntb-\ddf@cnta % no overflow possible because TeX's division truncates
\advance\ddf@cntb\dimen@ii % now numerator in \ddf@cntb is < denom
\count@\z@ % will store fractional part as a multiple of sp's
\ifnum\ddf@cntb>\z@
\ifnum\ddf@cnta>32768\relax
\ddf@cnta65536\relax
\loop
\ddf@cntc\dimen@ % denominator
\advance\ddf@cntc-\ddf@cntb
\ifnum\ddf@cntb<\ddf@cntc
\divide\ddf@cnta\tw@
\advance\ddf@cntb\ddf@cntb
\else
\ifnum\ddf@cntb=\ddf@cntc
\divide\ddf@cnta\tw@
\advance\count@\ddf@cnta
\ddf@cnta\z@ % abort the loop here
\else
\advance\count@\ddf@cnta % not same order as in previous branch!
\divide\ddf@cnta\tw@
\ddf@cnta-\ddf@cnta
\advance\ddf@cntc\ddf@cntc
\ddf@cntb\ddf@cntc
\fi
\fi
\ifnum\ddf@cnta=\z@\else % signed quantity: can not do if foo>\z@ ...
\repeat
% it is possible here that \count@ is 65536
% in case of a tie at the last unit the rounding was to even!
\else
% here denom <= 2^15=32768 (=0.5pt), hence 65536num <= 2^31 - 65536
\multiply\ddf@cntb65536\relax
% extra steps to do rounding
\ddf@cntc\ddf@cnta
\divide\ddf@cntc\tw@
\advance\ddf@cntb\ddf@cntc % no overflow possible
\ddf@cntc\ddf@cntb % need to keep copy for later branch
\divide\ddf@cntc\ddf@cnta
\count@\ddf@cntc
\ifodd\ddf@cnta
% odd denom, no tie possible
\else
\multiply\ddf@cntc\ddf@cnta
\ifnum\ddf@cntb=\ddf@cntc
% implement "ties go to even", the rounding was "up"
\ifodd\count@\advance\count@\m@ne\fi
\fi
\fi
% to get \count@ 65536 we would need to have N/D >= 65535.5/65536
% i.e. N/D >= 1 - 1/131072, but N/D<= 1 - 1/D, D<=32768, hence
% despite the rounding this branch always produces \count@ < 65536.
\fi
\fi
\dimen@\count@ sp\relax
% (\the\count@) % debug check
\expandafter\divdef@end\the\dimen@ #1%
}
\begingroup
\catcode`P 12
\catcode`T 12
\lowercase{\gdef\divdef@end #1.#2PT}#3{%
\advance\ddf@cntd #1\relax % almost always #1=0
\ifnum#2>\z@
\edef\x{\endgroup\edef\noexpand#3{\ddf@sgn\the\ddf@cntd.#2}}%
\else
\ddf@cntd\ddf@sgn\ddf@cntd
\edef\x{\endgroup\edef\noexpand#3{\the\ddf@cntd}}%
\fi
\x
}\endgroup
\input xinttools.sty
\def\TAB{&}\def\CR{\cr}
\tabskip 20pt
\halign {#\hfil &#\hfil \cr
\xintFor* #1 in {\xintSeq {1}{50}}\do
{\divdef\x \maxdimen{#1sp}\number\maxdimen/#1=\x
\ifodd #1 \TAB\else\expandafter\CR\fi
}}
Part B: a non-eTeX \Gscale@div
drop-in replacement
Here is an attempt to divide 8192
by 0.75
:
\Gscale@div\x {8192pt}{.75pt}
./betterdiv.tex:138: Arithmetic overflow.
<recently read> \dimen@ii
l.138 \Gscale@div\x {8192pt}{.75pt}
Here a pure Knuth TeX (*) approach to make a macro doing the precise
computation with guarantee of no overflow (if rounded theoretical exact value
is at most 16384-2/65536
.) I tried to follow the style of LaTeX and graphics.sty in using macros and temporary registers.
(*) the \loop
must like the LaTeX one allow \else\repeat
construct.
\documentclass{article}
\usepackage{graphicx}
\makeatletter
% new definition of \Gscale@div avoiding arithmetic overflows,
% (does NOT use e-TeX !... hence some sweat and efforts ...)
\def\Gscale@div#1#2#3{%
\setlength\dimen@{#3}%
\ifdim\dimen@=\z@
\PackageError{graphics}{Division by 0}\@eha
\dimen@#2%
\fi
\setlength\dimen@ii{#2}%
\ifdim\dimen@<\z@
\dimen@-\dimen@
\dimen@ii-\dimen@ii
\fi
\ifdim\dimen@ii<\z@
% Attention! \@tempa, \@tempb, \@tempc in use in graphics.sty across calls
\def\Gscale@sgn{-}\dimen@ii-\dimen@ii
\else
\let\Gscale@sgn\@empty
\fi
\@tempcnta\dimen@ % denominator
\@tempcntb\dimen@ii % numerator
\divide\@tempcntb\@tempcnta
\@tempdimb\@tempcntb\p@ % integer part of ratio. Naturally, may overflow!
\multiply\@tempcntb-\@tempcnta
\advance\@tempcntb\dimen@ii
\dimen@ii\@tempcntb sp\relax % now num<denom. No \@sp like \p@ ?
\count@\z@ % will store fractional part as a multiple of sp's
\ifdim\dimen@ii>\z@
\ifdim\dimen@>32768sp\relax
\@tempcnta65536\relax
\loop
\@tempdima\dimen@ % denominator
\advance\@tempdima-\dimen@ii
\ifdim\dimen@ii<\@tempdima
\divide\@tempcnta\tw@
\advance\dimen@ii\dimen@ii
\else
\ifdim\dimen@ii=\@tempdima
\divide\@tempcnta\tw@
\advance\count@\@tempcnta
\@tempcnta\z@ % abort the loop here
\else
\advance\count@\@tempcnta % not same order as in previous branch!
\divide\@tempcnta\tw@
\@tempcnta-\@tempcnta
\advance\@tempdima\@tempdima
\dimen@ii\@tempdima
\fi
\fi
\ifnum\@tempcnta=\z@\else % signed quantity: can not do if foo>\z@ ...
\repeat
\else
% here denom <= 2^15=32768 (=0.5pt), hence 65536num < 2^31
\multiply\@tempcntb65536\relax
\divide\@tempcntb\@tempcnta
\count@\@tempcntb
\fi
\fi
\dimen@\count@ sp\relax
\advance\dimen@\@tempdimb
\dimen@\Gscale@sgn\dimen@
\edef#1{\strip@pt\dimen@}%
}
\makeatother
%\usepackage{xinttools}
\begin{document}
% test
\makeatletter
% \xintFor* #1 in {\xintSeq {1}{100}}\do {
% \Gscale@div\x{1pt}{#1pt}
% % \Gscale@div\y{1pt}{-#1pt}
% % \Gscale@div\z{-1pt}{#1pt}
% % \Gscale@div\t{-1pt}{-#1pt}
% #1, \x, %\y, \z, \t
% }
% \xintFor* #1 in {\xintSeq {2}{100}}\do {
% \Gscale@div\x{32767sp}{#1sp}
% % \Gscale@div\y{1pt}{-#1pt}
% % \Gscale@div\z{-1pt}{#1pt}
% % \Gscale@div\t{-1pt}{-#1pt}
% #1, \x, %\y, \z, \t
% }
% \Gscale@div\x {1pt}{65536sp}
% 1pt/65536sp = \x
\Gscale@div\x {8192pt}{65535sp}
8192pt/65535sp = \x
\Gscale@div\x {8192pt}{.75pt}
8192pt/.75pt = \x
\makeatother
\end{document}

Part A: original answer
As an alternative with no package, you can define \Gscale@div
using e-TeX facilities.
\makeatletter
\def\Gscale@div #1#2#3{% defines #1 to be the ratio #2/#3, where #2 and #3
% are lengths (registers or expressions).
% The ratio #2/#3 should evaluate to less than 16384 in absolute value to
% avoid arithmetic overflow. It will be computed as fixed point
% number with about 4 or 5 digits after decimal mark.
\edef #1%
{\strip@pt\dimexpr
\numexpr\dimexpr#2\relax*65536/\dimexpr#3\relax\relax sp\relax}%
}
\makeatother

Full code (I have left original comments as in David's answer they may now be obsolete):
\documentclass{article}
\usepackage{graphicx}
\def\squaretext#1{%
\begin{tabular}{@{}l @{}r @{}}
\multicolumn{2}{c}{#1}\\
\rotatebox[origin=c]{90}{#1} & \rotatebox[origin=c]{270}{#1}\\
\multicolumn{2}{c}{\rotatebox[origin=c]{180}{#1}}\\
\end{tabular}%
}
\newdimen\scalefactor
\newdimen\outerboxwidth
\newdimen\innerboxwidth
\long\def\infinitesquares#1{%
\scalefactor=12pt
\outerboxwidth=20\scalefactor % any bigger results in arithmetic overflow
\noindent
\loop
\innerboxwidth=\dimexpr\outerboxwidth-\scalefactor
\resizebox{\outerboxwidth}{!}{\squaretext{#1}}%
\kern-\innerboxwidth%
\advance\outerboxwidth by -2\scalefactor
\advance\scalefactor by -.1\scalefactor % any different results in TeX capacity exceeded
\ifdim\outerboxwidth > \scalefactor
\repeat
}
\makeatletter
\def\Gscale@div #1#2#3{% defines #1 to be the ratio #2/#3, where #2 and #3
% are lengths (registers or expressions).
% The ratio #2/#3 should evaluate to less than 16384 in absolute value to
% avoid arithmetic overflow. It will be computed as fixed point
% number with about 4 or 5 digits after decimal mark.
\edef #1%
{\strip@pt\dimexpr
\numexpr\dimexpr#2\relax*65536/\dimexpr#3\relax\relax sp\relax}%
}
\makeatother
\begin{document}
\def\knuth{This is \TeX, a document compiler intended to produce typesetting of high quality.} % texdoc tex, line 1
\def\ezekiel{And the altar shall be twelve cubits long, twelve broad, square in the four squares thereof.} % Ezekiel 43:15, KJV
\errorcontextlines500
\infinitesquares{\knuth}
\vfill
\infinitesquares{\ezekiel}
\end{document}