如何缓存宏的结果

如何缓存宏的结果

TeX 作为一种编程语言的能力可以用来生成包含相当复杂计算的文档。虽然不是每个人都喜欢,但这种文档类似于文学编程,因为您可以描述要计算的内容,以及执行计算。

如何排版大数字,我使用一个简单的宏来计算梅森素数对于 1279,编译需要几秒钟。(使用其他带有大整数库的脚本语言时,编译速度也会明显变慢)。

我如何缓存宏的结果,以便在后续运行中不再重复计算?

我在想办法\pdfmdfivesum为文件名创建哈希值,并使用它来缓存结果。使用哈希值的原因是,人们可能想要使用不同的值来调用宏 - 因此 md5 哈希值可以是宏名称加上值。

答案1

如果宏的输出完全可扩展,我会将其存储在另一个宏中,该宏也会写入文件.aux。该存储宏的名称应该是通用的,以便计算宏可以测试它是否存在,如果存在,则只需重复使用它。如果输入会导致内部出现问题,您可以使用从输入计算出的 MD5 校验和作为宏名称的一部分,\csname ... \endcsname但对于数字等来说,这不是必需的。

使用梅森计算作为示例:

\documentclass{article}
\usepackage[english]{babel}
\usepackage{numprint}
\usepackage{bigintcalc}
\begin{document}
\npthousandsep{ }
\makeatletter
\def\Mersenne#1{%
  \begingroup
    \par\noindent\parindent=0pt
    $M_{#1}=$\par
    % Calculate if not defined yet
    \@ifundefined{Mersenne@#1}{%
        \def\exponent##1{\bigintcalcPow{2}{##1}}%
        \expandafter\xdef\csname Mersenne@#1\endcsname{%
            \bigintcalcSub{\exponent{#1}}{1}%
        }%
    }{}%
    % Write to aux file
    \immediate\write\@auxout{\noexpand\expandafter\gdef\noexpand\csname Mersenne@#1\noexpand\endcsname{\csname Mersenne@#1\endcsname}}%
    % Print
    \expandafter\numprint\expandafter{\csname Mersenne@#1\endcsname}%
  \endgroup
}
\makeatother

\Mersenne{1279}
\end{document}

然后文件.aux包含以下行,只要.aux没有被删除或者由于编译错误而没有正确写入,就可以避免将来的重新计算:

\expandafter \gdef \csname Mersenne@1279\endcsname {10407932194664399081925240327364085538615262247266704805319112350403608059673360298012239441732324184842421613954281007791383566248323464908139906605677320762924129509389220345773183349661583550472959420547689811211693677147548478866962501384438260291732348885311160828538416585028255604666224831890918801847068222203140521026698435488732958028878050869736186900714720710555703168729087}

如果宏的输出不是完全可扩展的,甚至是脆弱的(即\edef会导致错误),那么它可能会存储在一个框寄存器中。但这有几个缺点:它不能.aux轻易地存储在文件中,因此在一次编译运行中,同一宏的多次使用是有限的。此外,排版也是固定的,例如,长数字的换行不会因每次使用而有所不同。

相关内容