重构 TeX/LaTeX 代码

重构 TeX/LaTeX 代码

下面是我编写的一些代码的简化版本,可以自动地将数字从十进制格式化为科学计数法。我已经用了一段时间了,并且有一些想法如何将它与我做过的其他工作结合起来,形成一个用于工程计算的小包。然而,回顾这几个小时的工作,它肯定需要好好整改一下。

代码提供了两个主要的作者命令\snotation{},并\enotation{}以科学或工程符号返回输入的数字。

我更倾向于追求代码的可读性,而不是算法的优雅性,我发现编写代码比事后通读并修改代码更容易。循环和 if 结构对于 TeX 来说都不是很可靠,我选择“剪切和粘贴代码”,而不是使用这些更容易出错的 TeX 结构部分。

在哪里可以找到有关重构和完善 TeX 代码的信息。您有什么好的策略或提示和建议吗?

这是可工作的最小代码(不包括工程部分)。

\documentclass{article}
\usepackage{fp,siunitx}
\begin{document}

\gdef\SetNumDecimals#1{\gdef\numdecimals{#1}}
\SetNumDecimals{10}
%% Helper routine for formatting numbers
%% first it round to 4 decimal numbers
%% then it clips the number so that if trailing
%% zeroes exist it removes them prints 16.01 and not 16.010000000
\newcommand\Clip[1]{\FPround\tmp{#1}{\numdecimals}\FPclip\tmp{\tmp}\tmp}%
\newcommand\Clipsmall[1]{\FPclip\tmp{#1}\tmp}%

\gdef\typeset#1#2{
  \def\clippednumber{\Clip{#1}}
  \def\powers##1{$##1 \times10^{#2}$}
  \powers{\clippednumber}
 }

\gdef\typesetsmall#1#2{
  \def\clippednumber{\Clipsmall{#1}}
  \def\powers##1{$##1 \times10^{#2}$}
  \powers{\clippednumber}
 }

\FPset\PowerOne{10}
\FPset\PowerTwo{100}
\FPset\PowerThree{1000}
\FPset\PowerFour{10000}
\FPset\PowerFive{100000}
\FPset\PowerSix{1000000}
\FPset\PowerSeven{10000000}
\FPset\PowerEight{100000000}
\FPset\PowerNine{1000000000}
\FPset\PowerTen{10000000000}
\FPset\PowerEleven{100000000000}
\FPset\PowerTwelve{1000000000000}
\FPset\PowerFifteen{1000000000000000}

\gdef\Epower{}
\gdef\result{}

\def\Powers#1{%
\FPset\Number{#1}
\FPifgt\Number\PowerTwo
   \FPdiv\temp{\Number}{\PowerTwo}
   \def\Epower{3}
   \FPset\result\temp
\fi
\FPifgt\Number\PowerThree
   \FPdiv\temp{\Number}{\PowerThree}
   \def\Epower{3}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerFour
   \FPdiv\temp{\Number}{\PowerFour}
   \def\Epower{4}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerFive
   \FPdiv\temp{\Number}{\PowerFive}
   \def\Epower{5}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerSix
   \FPdiv\temp{\Number}{\PowerSix}
   \def\Epower{6}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerSeven
   \FPdiv\temp{\Number}{\PowerSeven}
   \def\Epower{7}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerEight
   \FPdiv\temp{\Number}{\PowerEight}
   \def\Epower{8}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerNine
   \FPdiv\temp{\Number}{\PowerNine}
   \def\Epower{9}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerTen
   \FPdiv\temp{\Number}{\PowerTen}
   \def\Epower{10}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerEleven
   \FPdiv\temp{\Number}{\PowerEleven}
   \def\Epower{11}
   \global\let\result\temp
\fi

\FPifgt\Number\PowerTwelve
   \FPdiv\temp{\Number}{\PowerTwelve}
   \def\Epower{12}
   \global\let\result\temp
\fi
  \typeset{\result}{\Epower}
}

\FPset\one{1}

\def\piconums#1{%
\FPset\Number{#1}
\FPiflt\Number\one
   \FPmul\temp{\Number}{\PowerOne}
   \def\Epower{-1}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerTwo}
   \def\Epower{-2}
   \global\let\result\temp
 \else
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerThree}
   \def\Epower{-3}
   \global\let\result\temp
 \else
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerFour}
   \def\Epower{-4}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerFive}
   \def\Epower{-5}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerSix}
   \def\Epower{-6}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerSeven}
   \def\Epower{-7}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerEight}
   \def\Epower{-8}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerNine}
   \def\Epower{-9}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerTen}
   \def\Epower{-10}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerEleven}
   \def\Epower{-11}
   \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerTwelve}
  \def\Epower{-12}
  \global\let\result\temp
\fi
\FPiflt\result\one
  \FPmul\temp{\Number}{\PowerFifteen}
  \def\Epower{-15}
  \global\let\result\temp
\fi

\typesetsmall{\result}{\Epower}
}

%% main routine
\def\snotation#1{
\FPset\Number{#1}
\FPifgt\Number\one
    \Powers{#1}
   \else
    \piconums{#1}
\fi}

\snotation{0.000000100326}

\snotation{1133009.1495978707}
\end{document}

对于代码的长度深表歉意。

答案1

我不确定是否有一个重构 TeX 代码的好指南,但我从上面注意到的几件事您可能需要考虑:

  • 进行全局分配时,您应该始终思考“这真的有必要吗?”。虽然将事物全局化通常很容易,但其他方法有时更好,例如

      \def\TempResult{Result}%
      \expandafter\endgroup
    \expandafter\def\expandafter\RealResult\expandafter{\TempResult}%
    
  • 注意如何处理\fi。请记住,除非您扩展条件的末尾,否则它们会继续堆积,并可能导致失控条件或堆栈耗尽。这就是为什么诸如

      \expandafter\NextFunction
    \fi
    

    或者

    \if<something>
      \expandafter\@firstoftwo
    \else
      \expandafter\@secondoftwo
    \fi
      {True code}
      {False code}%
    

    非常常见(通常第二个是预先包装好的,例如etoolbox

  • 除非您想要获得最佳性能,否则我建议使用更多、命名良好的宏,而不是更少的长宏,并且更倾向于使用宏而不是原语(例如,so\@namedef而不是\expandafter\csname ...\endcsname)。(如果您真的追求最佳性能,那么即使额外的\expandafters 也会有所不同,但除非您正在编写低级内核函数,否则这应该不是问题!)

答案2

由于以fp十进制存储其数字,我只需计算数字的数量,或者除此之外,使用对数来计算指数。

作为更一般的规则,TeX 中的循环非常容易使用。

\loop
    % stuff that always happens
    \if... % the loop condition
    % stuff that happens if the condition is true
\repeat

我倾向于编写如下循环

\loop\if... % whatever the condition is
    % loop body
\repeat

这是一个完整的例子。

\catcode`@=11
\count@=0
\loop\ifnum\count@<256
    \char\count@\
    \advance\count@ by1
\repeat
\bye

答案3

如果你不想使用循环(如上所述,虽然普通的 TeX 版本不应该嵌套,但效果很好),您可以通过定义宏来完成这项工作,从而避免重复的代码。例如,您的一段代码可以重写为

\def\myFPifgt #1#2{
    \FPifgt\Number#1
        \FPdiv\temp{\Number}{#1}
        \def\Epower{#2}
        \global\let\result\temp
    \fi
}

\myFPifgt {\PowerThree} {3}
\myFPifgt {\PowerFour} {4}
\myFPifgt {\PowerFive} {5}
\myFPifgt {\PowerSix} {6}

%etc.

相关内容