7

My thesis includes numbers such as, 9.368e-03, OR 9.368E-03, spread throughout the main text. I would like to typeset them in the form of a scientific notation such as - 9.683 x 10^-3.

However, since I am using TeX Live 2009 on an equally ancient machine and since my thesis document has grown considerably large, I do not want to burden the system by using any of the dedicated packages (e.g. siunitx), just to typeset a few numbers properly.

Is there a simpler way by which I can typeset my numbers in the desired format without using a dedicated scientific notation package?

  • 1
    Does you editor have "change all"? – John Kormylo May 27 '15 at 3:27
  • @JohnKormylo I can't understand your question. Could you please elaborate? – Amar May 27 '15 at 4:45
  • 1
    @Amar Using a suitable search set up (probably a regular expression), you could use your editor to simply change the source from 9.368e-03 to $9.368\times10^{-3}$, which would do the job. In any case you will need to search your text for the numbers to add in whatever mark-up you decide to go with. – Joseph Wright May 27 '15 at 6:06
  • @JosephWright Ahh! I am aware of replacing the main input text itself in the manner you suggest. However, I'd rather maintain my input text as it is and simply print out the desired result in PDF using some form of TeX trickery! :) In my experience, it's better to keep your data unchanged, as it allows me to perform quick editing operations, if need be. e.g., to replace some data from the input text, a quick copy/cut/paste between the data file & the input text is sufficient; since, TeX commands will take care of the typesetting using the input format. Hope that explains it. :) – Amar May 27 '15 at 12:41
8

For the simple format given, a short chain of dedicated commands can pick up the number. I'm assuming here that the numbers will never have too many digits for TeX's \number primitive, which I'm using to trim off any leading zeros.

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

If you want to retain leading zeros and any leading + symbols the code can be slightly simplified

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

More complex parsing is possible without using siunitx, and indeed the numprint package offers quite a bit of this in a package that has been available for many years.


How does the above code work? The outer macro

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

simply grabs the entire input, and inserts it after the first internal macro \num@auxi. The latter is going to look for a e, so we make sure there will be one to find by including ee after the input. (I'll come back to why two e tokens later.)

Macro \num@auxi comes next

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

Here we have a delimited macro. Everything up to the first e will be grabbed as #1, everything between that and the second e as #3 and the remainder up to \stop as #3. There are two outcomes. If the original input contains an e then #1 will be the mantissa, #2 will be the exponent and #3 is junk. On the other hand, if there was no e then #1 is the entire number and #2 is empty. We test for that using \ifx\relax#2\relax (true if #2 is empty) and branch accordingly.

If e was not found, there is a bit of set up to do the same again but looking for an E. Once that search is done, we have two outcomes: a number with no exponent or a number with exponent. The first case is handled by

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

Due to the way I've set up the code, this receives two arguments, the mantissa and the exponent. We know the latter is empty (it's only there to act as a 'throw away') so we just insert #1 (the mantissa). I've included \number before it, which means TeX will 'tidy up' the input, removing any leading zeros or + signs.

If there is an exponent then the code

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

is used: this inserts the mantissa then the exponent with correct formatting. I could have combined the last two macros and included a test on #2 there, but I felt it was clearer with separate paths.


You might wonder in the above why we have

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

rather than just using one e (as the input can only have one). It all comes down to making the tests as short as possible. With a definition

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

you might think we'll be OK. However, there's a problem. If I do

\num@auxi#1\stop

and there is no e in the input then TeX will complain as the parameters for \num@auxi will not match properly. So instead we need to do

\num@auxi#1e\stop

to make sure that there is always an e to find. However, if the input also contains an e then \num@auxi ends up splitting so that #1 is the mantissa but #2 is the exponent plus that trailing e. We could allow for that will a clean-up step, but it's easier to use two e tokens and use definition

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

used as

\num@auxi#1ee\stop

In this case, if there is no e in the input we get #1 as the mantissa, while #2 and #3 are empty. On the other hand, if there was an e in the input then #1 is the mantissa, #2 is the exponent and #3 mops up the stray e (we always discard #3). So working this way we need only the one macro to do the work.

  • Parsing a known, fixed, format can always be done quite quickly: packages such as siunitx or numprint come in when you want to deal with multiple formats or where you don't want to worry about the complexities of writing your own parser. For example, life gets a bit more tricky if you want to retain a leading + but drop any leading 0, or want to remove trailing 0, or ... – Joseph Wright May 27 '15 at 6:31
  • Thank you for your solution and some extensive code for parsing. However, for no fault of yours, I don't really understand what's happening in the solution you've provided. All I see are some TeX control sequences interspersed between bunch of conditional statements that somehow re-define the TeX's \number primitive. How exactly, I have no clue about that! :| – Amar May 28 '15 at 17:08
  • @Amar No, I would never redefine \number! I'll add some comments in a bit. – Joseph Wright May 28 '15 at 17:12
  • Wow! Impressive! A very clear explanation. Thank you! .. Just one more question :) .. Why two e/ E's? The input number will always have one e/ E representing the beginning of the exponent. Is it a parsing requirement? – Amar May 29 '15 at 13:55
  • @Amar See update: it's a bit too complex for a comment. (It's also a general trick: might make a good generic question if we don't already have it.) – Joseph Wright May 29 '15 at 14:10
2

This solution is based on xstring package's \StrSubstitute command. It substitutes every occurrence of X from the selected string element by Y. A new command is defined, which uses \StrSubstitute to remove the e OR E from the input number (9.368e-03 or 9.368E-03) and typesets it in the form of a scientific notation, i.e. 1.536×10^-01. Rest is self-explanatory.

Note 1: If the user forgets to write e or E in the input, this method will still work!
Note 2: For numbers that include E instead of e, the user must use the \sciE method from the solution. The first method, i.e. \sci will fail in this particular case!
Disclaimer: This is just one of the many ways in which one can typeset numbers into scientific notation. Also, this solution is based on the assumption that some manual labour is acceptable!

Minimal Working Example:

\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 Output :

Output of the code given above:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.