如何在不使用专用包(如 siunitx)的情况下以科学计数法排版数字?

如何在不使用专用包(如 siunitx)的情况下以科学计数法排版数字?

我的论文包括诸如 、9.368e-03或 之类的数字9.368E-03,它们遍布正文。我想以科学记数法的形式排版它们,例如 - 9.683 x 10^-3

但是,由于我正在使用TeX Live 2009在同样古老的机器上,由于我的论文文档已经变得相当大,我不想通过使用任何专用包(例如siunitx)来增加系统负担,只是为了正确排版几个数字。

有没有更简单的方法可以让我以所需的格式排版数字,而无需使用专门的科学计数法包?

答案1

对于给定的简单格式,一小段专用命令就可以获取数字。我在这里假设这些数字对于 TeX 的\number基元来说永远不会有太多的数字,我用它来修剪任何前导零。

\documentclass{article}
\makeatletter
\newcommand*{\num}[1]{%
 \ensuremath{%
   \num@auxi#1ee\stop
  }%
}
\newcommand*\num@auxi{}
\def\num@auxi#1e#2e#3\stop{%
  \ifx\relax#2\relax
    \expandafter\num@auxii
  \else
    \expandafter\num@auxv
  \fi
    {#1}{#2}%
}
\newcommand*\num@auxii[2]{%
  \num@auxiii#1EE\stop
}
\newcommand*\num@auxiii{}
\def\num@auxiii#1E#2E#3\stop{%
  \ifx\relax#2\relax
    \expandafter\num@auxiv
  \else
    \expandafter\num@auxv
  \fi
    {#1}{#2}%
}
\newcommand*\num@auxiv[2]{%
  \number #1 
}
\newcommand*\num@auxv[2]{%
  \number #1 \times 10^{\number #2 }%
}
\makeatother
\begin{document}
\num{9.386e-03}
\num{9.386E-03}
\num{9.386}
$\num{9.386e-03}$
\end{document} 

如果你想保留前导零和任何前导+符号,代码可以稍微简化

\documentclass{article}
\makeatletter
\newcommand*{\num}[1]{%
 \ensuremath{%
   \num@auxi#1ee\stop
  }%
}
\newcommand*\num@auxi{}
\def\num@auxi#1e#2e#3\stop{%
  \ifx\relax#2\relax
    \expandafter\num@auxii
  \else
    \expandafter\num@auxiv
  \fi
    {#1}{#2}%
}
\newcommand*\num@auxii[2]{%
  \num@auxiii#1EE\stop
}
\newcommand*\num@auxiii{}
\def\num@auxiii#1E#2E#3\stop{%
  \ifx\relax#2\relax
    \expandafter\@firstoftwo
  \else
    \expandafter\num@auxiv
  \fi
    {#1}{#2}%
}
\newcommand*\num@auxiv[2]{%
  #1 \times 10^{#2}%
}
\makeatother
\begin{document}
\num{9.386e-03}
\num{9.386E-03}
\num{9.386}
$\num{9.386e-03}$
\end{document}

更复杂的解析是可能的siunitx,而不需要使用numprint这个软件包中提供了相当多这样的功能,并且这个软件包已经使用了很多年。


上面的代码是如何工作的?外部宏

\newcommand*{\num}[1]{%
 \ensuremath{%
   \num@auxi#1ee\stop
  }%
}

只需抓取整个输入,并将其插入到第一个内部宏之后\num@auxi。后者将寻找一个e,因此我们确保在ee输入后包含一个。(稍后我会回来解释为什么是两个e标记。)

\num@auxi接下来是宏观

\def\num@auxi#1e#2e#3\stop{%
  \ifx\relax#2\relax
    \expandafter\num@auxii
  \else
    \expandafter\num@auxv
  \fi
   {#1}{#2}%
}

这里我们有一个分隔宏。第一个之前的所有内容都e将被抓取为 ,介于 和第二个之间的所有内容将被抓取为,#1直到的余数将被抓取为。结果有两种。如果原始输入包含 ,则将是尾数,将是指数并且是垃圾。另一方面,如果没有 ,则是整个数字并且为空。我们使用(如果为空则为真)进行测试并相应地进行分支。e#3\stop#3e#1#2#3e#1#2\ifx\relax#2\relax#2

如果e没有找到,则需要进行一些设置以再次执行相同的操作,但要寻找E。搜索完成后,我们有两个结果:一个没有指数的数字或一个有指数的数字。第一种情况由

\newcommand*\num@auxiv[2]{%
  \number #1 
}

由于我设置代码的方式,它接收两个参数,尾数和指数。我们知道后者是空的(它只是作为“丢弃”的),所以我们只需插入#1(尾数)。我在\number它前面已经包含了,这意味着 TeX 将“整理”输入,删除任何前导零或+符号。

如果有指数,则代码

\newcommand*\num@auxv[2]{%
  \number #1 \times 10^{\number #2 }%
}

被使用:这会插入尾数,然后插入格式正确的指数。我本可以将最后两个宏组合起来,并在#2其中进行测试,但我觉得使用单独的路径会更清晰。


你可能会想知道为什么我们

\def\num@auxi#1e#2e#3\stop{%

而不是只使用一个e(因为输入只能有一个)。这一切都归结为使测试尽可能短。使用定义

\def\num@auxi#1e#2\stop{%

你可能会认为我们会没事的。然而,有一个问题。如果我这样做

\num@auxi#1\stop

e并且输入中没有,那么 TeX 会抱怨,因为的参数\num@auxi无法正确匹配。因此我们需要这样做

\num@auxi#1e\stop

以确保始终有一个e要查找的。但是,如果输入还包含一个,e\num@auxi最终会分裂,因此#1是尾数,但#2指数加上尾随的。我们可以允许这样做,这将是一个清理步骤,但使用两个标记并使用定义e更容易e

\def\num@auxi#1e#2e#3\stop{%

用作

\num@auxi#1ee\stop

e在这种情况下,如果输入中没有,我们将得到#1尾数,而#2#3为空。另一方面,如果e输入中有,那么#1就是尾数,#2是指数,并#3清除杂散e(我们总是丢弃#3)。所以以这种方式工作,我们只需要一个宏来完成工作。

答案2

此解决方案基于xstring包的\StrSubstitute命令。它替换每个出现的X从选定的字符串元素中Y。定义了一个新命令,用于从输入数字(或)中\StrSubstitute删除e或,并将其排版为科学计数法的形式,即。其余的是不言自明的。E9.368e-039.368E-031.536×10^-01

注1: 如果用户忘记写 e 或者 E 在输入中,此方法依然有效!
笔记2: 对于包含的数字 E 代替 e,用户必须使用 \sciE 方法。第一种方法,即 \sci 在这种特殊情况下将会失败!
免责声明:这只是将数字排版为科学计数法的众多方法之一。此外,此解决方案基于可以接受一些手工劳动的假设!

最小工作示例:

\documentclass{article}
\usepackage{booktabs}
\usepackage{xstring} % for text replacement
\usepackage{xcolor}
\providecommand{\sci}[1]{\protect\ensuremath{\times 10^{\StrSubstitute[0]{#1}{e}{}}}}
% ---- for numbers in format: 9.368e-03 (i.e., numbers using e)
% \sci will remove "e" from the input and typeset the result as:- \times 10^
% \StrSubstitute[0]{#1}{e}{} from the command substitutes "e" by nothing i.e. null!
% usage: if 1.536e-01 is to be converted then -- 1.536\sci{e-01} gives 1.536×10^-01

\providecommand{\sciE}[1]{\protect\ensuremath{\times 10^{\StrSubstitute[0]{#1}{E}{}}}}
% ---- for numbers in format: 9.368E-03 (i.e., numbers using E)

\begin{document}
{\noindent\Large 1.536e-01 is the input number, which we would like to\\[8pt]
convert to a number in scientific notation, like so \textemdash}\\[0.35in]
%
\hspace*{\fill}{\huge \fcolorbox{cyan!25}{cyan!15}{1.536\sci{e-01}}}\hspace*{\fill}
\vspace*{0.3in}
{                                   % Begin group -- To keep the effect local!
\renewcommand*{\arraystretch}{1.75}
\begin{table}[h]
\large
\begin{center}
\begin{tabular}{@{\extracolsep{\fill}}@{\hskip 3em}c@{\hskip 6em}c@{\hskip 3em}@{}}
\toprule
\textbf{qValue} & \textbf{qValueRes}\\
\midrule
9.368\sci{e-03} & 2.180\sci{e-02} \\
1.058\sci{e-06} & 1.411\sci{e-03} \\
2.563\sci{e-02} & 5.281\sci{e-02} \\
\colorbox{gray!50}{1.536e-01} & \colorbox{gray!50}{1.536e-01} \\ % original numbers!
\colorbox{gray!50}{1.536e-01} & \colorbox{gray!50}{1.536e-01} \\ % original numbers!
1.536\sci{e-01} & 1.536\sci{e-01} \\
2.563\sci{e-02} & 5.281\sci{e-02} \\
\bottomrule
\end{tabular}
\end{center}
\caption{Test}
\label{tab:test}
\end{table}
}                                   % End group -- To keep the effect local!
\end{document}

MWE 输出:

上面给出的代码的输出:

相关内容