下面是我编写的一些代码的简化版本,可以自动地将数字从十进制格式化为科学计数法。我已经用了一段时间了,并且有一些想法如何将它与我做过的其他工作结合起来,形成一个用于工程计算的小包。然而,回顾这几个小时的工作,它肯定需要好好整改一下。
代码提供了两个主要的作者命令\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
)。(如果您真的追求最佳性能,那么即使额外的\expandafter
s 也会有所不同,但除非您正在编写低级内核函数,否则这应该不是问题!)
答案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.