让我的无限方格具有数学证明

让我的无限方格具有数学证明

我创建了一个命令,可以制作一个不断减小的正方形文本,以产生无限减小的效果。但是,如果我增加起始宽度或更改比例因子,TeX 就会发生算术溢出或内存溢出。我希望我有数学技能来理解为什么会这样。

我怎样才能使其更加健壮,以便我可以从任意尺寸开始并改变缩放因子?

在此处输入图片描述

(如果您想用颜色或其他东西让它变得更漂亮,我不会反对。)

\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=18\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
}

\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

\infinitesquares{\knuth}

\vfill

\infinitesquares{\ezekiel}

\end{document}

答案1

更新缩小的问题graphicx已在下一个版本(可能是 2017 年 1 月)的开发源中得到修复,并且评论中讨论的 xetex 驱动程序的问题已得到修复并已在 CTAN 上发布。


主要问题是,图形中的除法宏被编写为在不使用超过几十个字节的代码的情况下对正常图像缩放范围进行合理的处理。基本上它在这里失败了。

expl3您可以使用更为准确的除法(并且使用几个数量级的更多代码:-)

然后,您就避免了算术溢出,尽管如果推得太远,您就会耗尽主内存,除非您开始摆弄 texmf.cnf 或使用 luatex 和动态内存分配。

在此处输入图片描述

\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
}

\usepackage{expl3}
\ExplSyntaxOn
\cs_set:cpn { Gscale@div } #1 #2 #3
 {
  \cs_set:Npx #1
   {
    \fp_to_decimal:n
     {
      \dim_to_decimal_in_sp:n { #2 } / \dim_to_decimal_in_sp:n { #3 }
     }
   }
 }
\ExplSyntaxOff

\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}

答案2

您的代码中也存在一个真正的数学问题。我们将S您的scalefactorT您的称为outerboxwidth,并且l您用于迭代的小值S称为S->S-l S。因此在我复制的代码中l是。此外,最初假设您设置了。为了使您的循环不无限,可以得出以下结论应该为真:0.1T=NS

N < 2/l

因此,对于l=0.1,条件是N < 20。对于l=0.2,条件是N < 10。对于 ,l=0.5条件将是N < 4。实际上,它似乎对l=0.1和都有效N=20,但我猜舍入误差会合谋帮助循环终止。(请参阅本文结尾。)

数学是几何级数。我们把 写成m=1-l,那么经过 n 次迭代后,可以得到

S_n = m^n S_0
T_n = T_0 - 2S_0 (1+m+..+m^{n-1})

的极限值T

T_0 - 2S_0 1/(1-m) = (N - 2/l) S_0

因此,如果N - 2/l >= 1,则所有的T总是> S_0,并且循环是无限的。

n实际上,如果对于某个,,则循环终止T_n <= S_n,我们将其转化为

N - 2(1-m^n)/l <= m^n 
N - 2/l + (2/l -1) m^n <= 0        (*)

由于0<l<1,我们有2/l - 1 > 1。因此,上述不等式只有 才能实现N < 2/l。并且如果N < 2/l,那么对于足够大的n, (*) 成立是正确的。

因此,终止的数学条件是 。然而,有人观察到它对和N < 2/l都有效:我没有详细研究过,但某种舍入效应应该是有助于循环终止的解释。对于我得到的代码要用 来完成,但它会 引发。N=20l=0.1l=0.1N=20.05TeX capacity exceededN=20.06

TeX capacity exceeded与类似N=4.01l=0.5但它可以用 进行编译N=4

这全都是用\Gscale@div我的其他答案中的。

答案3

大卫·卡莱尔 (David Carlisle) 的诊断表明,罪魁祸首是graphics\Gscale@div。确实,请注意所采用的算法可能会产生溢出,一个典型的例子是除以8192(0.75理论上,应该允许将其除以尽可能小的0.5+epsilon,以遵守 的<16384结果约束\maxdimen=16384pt-1sp,前提是最终结果本身是通过\the应用于 dimen 寄存器产生的)

此答案现在有四个部分A,B,C,D,按C+D,B,A的顺序显示。

  • 答:原始答案定义了一个单行替换,用于\Gscale@div除以两个长度,使用 e-TeX(并跳过原始所做的一些检查\Gscale@div)。我知道这个网站上的其他地方有类似的表达,我最近遇到了它,我记得它是在 2011 年或 2012 年的一些帖子中。

  • B:\Gscale@div不使用 e-TeX 工具,而是使用 LaTeX 常用的暂存宏和寄存器编写的替代方法。如果(舍入)结果最多为,则保证计算不会产生溢出。16384 - 2/65536如下所述,当除数最多为0.5pt截断,但当它至少是0.5pt一个四舍五入精确比率的整数倍数为sp单位 (= 1/65536)。对于希望在所有情况下都进行四舍五入以保持一致性的人,请参阅 D 部分。

  • C:这里最上面是一个\divdef用于划分两个 TeX 维度的宏,对结果的大小没有任何限制。最初,我从 B 开始编写它,并考虑了除法计数,但由于结果是一个固定小数点,标记后最多有五位数字,而将其用作 TeX 输入的唯一方法(本机,没有额外的代码行)是将其视为维度(通常以 pt 为单位),最后我再次假设输入是维度寄存器或规范(部分\setlength被删除 --- 以及calc 使用包时的开销 --- 因为这是为了在 Plain 中也可用而编写的。)这可以直接在 Plain TeX 中使用。宏\divdef\Gscale@div或部分 B 的一个非常小的变体,它利用了后者将整数部分与小数部分分开的事实(但代码的某些部分使用计数操作,而\Gscale@div部分 B 使用维度)。我犹豫是否再次使用\the维度进行最终转换为十进制写作,因为它可以用其他方式处理,但人们不得不担心恢复与 TeX 通过完全相同的舍入\the。该比率R计算为最接近的整数倍1/65536(平局为偶数;但请参阅下一项以获得更精确的描述),然后(其小数部分)通过 TeX 的 转换为十进制数\the

  • D:实际上 C 和 B 中的代码有两个分支;上述关于舍入的描述适用于除数为 的情况>0.5pt。对于除数,最多0.5pt分数为截断,不舍入,到最接近的倍数1/65536,然后通过转换为十进制扩展\the。因此在部分 D 中,代码被修改为始终进行舍入,平分到偶数。我对此犹豫不决,因为TeX\divide截断而不是舍入。另一方面,e-TeX/运算符(顺便说一下,它只允许整数除数)舍入(这有时会引起烦恼),但它从零开始舍入,不遵守“平分到偶数”规则。

注 1:当整数部分很大时,4 或 5 位小数自然是虚幻的精度,因为我们划分的维度可能已经包含了精度低得多的舍入。但它是评估整数比率的数学精确结果,在内部将两个维度编码为 sp 单位的整数倍。

注 2:由于结果可能(很大程度上!)超过单位\maxdimen的倍数pt,C 和 D 中的代码应该设置一个标志来告知何时出现这种情况,以便后续例程可以根据此做出决策。

C+D 部分。“划分两个维度并输出一个定点数(标记后最多有 4 或 5 个小数)”宏,对大小没有任何条件(不使用 e-TeX,为 Plain 编写)

下图展示了除法中除数较小的情况,因此截断操作如上所述。请注意,为了进行比较,如果

\dimen@ 3pt
\divide\dimen@ by 10
\the\dimen@

TeX 会打印0.29999pt,这与下面观察到的结果一致,例如,当 除以 时\maxdimen10这是因为当除数较小(最多小于0.5pt)时,下面的代码会截断精确的比率。

在此处输入图片描述

但是,当使用在所有情况下都进行四舍五入的 D 部分代码时,现在的情况是相同的:(观察差异)

在此处输入图片描述

在这两种情况下, 都说明了一个有趣的问题1073741823/37。如果我们直接进行十进制扩展(没有中间的四舍五入/截断为 的整数倍1/65536),则正确的小数部分是.27027...(并且略大)。但由于中间步骤(如 C 部分或 D 部分代码中所示),我们最终得到的是.27026小数部分。

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

D 部分的代码(仅在分支中的行有所不同denom <= 2^15=32768):

\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
}}

B 部分:非 eTeX\Gscale@div嵌入式替代品

以下是尝试除以8192的示例0.75

\Gscale@div\x {8192pt}{.75pt}

./betterdiv.tex:138: Arithmetic overflow.
<recently read> \dimen@ii 

l.138 \Gscale@div\x {8192pt}{.75pt}

这里采用纯 Knuth TeX (*) 方法制作一个宏来执行精确计算并保证不溢出(如果舍入的理论精确值最多为16384-2/65536)。我尝试遵循 LaTeX 和 graphics.sty 的风格来使用宏和临时寄存器。

(*)\loop必须像 LaTeX 那样允许\else\repeat构造。

\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}

在此处输入图片描述

A 部分:原始答案

作为没有包的替代方案,您可以定义\Gscale@div使用 e-TeX 设施。

\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

在此处输入图片描述

完整代码(我留下了原始评论,因为在 David 的回答中它们现在可能已经过时了):

\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}

相关内容