Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Background:

  • I want all decimal numbers in my TeX input file use . as the decimal separator.
  • If my document is translated to German (for example), the . can be globally converted to , by locale option.
  • Now consider if I want to output (1,2+3,4) m in the translated version but (1.2+3,4) m in the original version.
  • Using $\num{1.2}+\num{3.4}$\si{\m}$ produces an output with incorrect spacing between the ) and m.
  • Using $\SI{(1.2+3.4)}{\m}$ throws an error.
  • Using $\SI[parse-numbers=false]{(1.2+3.4)}{\m}$ will ignore locale=DE option so the output will use . rather than ,.
  • Using $\SI[parse-numbers=false]{(1{,}2+3{,}4)}{\m}$ will make my translator unhappy.

MWE:

enter image description here

\documentclass[preview,border=12pt,varwidth]{standalone}

\usepackage{amsmath}
\usepackage[locale=DE]{siunitx}

\def\x{1.23}
\def\y{4.56}

\def\X{1{,}23}
\def\Y{4{,}56}
\begin{document}
$\!
\begin{aligned}[t]
L &= \SI{\x}{\m} + \SI{\y}{\m}\\
    &= (\num{\x}+\num{\y})\si{\m}
\end{aligned}
$

$\!
\begin{aligned}[t]
L &= \SI{\x}{\m} + \SI{\y}{\m}\\
    &= \SI[parse-numbers=false]{(\x+\y)}{\m}
\end{aligned}
$

$\!
\begin{aligned}[t]
L &= \SI{\x}{\m} + \SI{\y}{\m}\\
    &= \SI[parse-numbers=false]{(\X+\Y)}{\m}
\end{aligned}
$


\end{document}

Questions:

Is there a more convenient way to represent (1,2+3,4) m in the translated version without using parse-numbers=false and xxx{,}yyy ugly trick while maintaining the correct spacing?

share|improve this question
    
$(\num{\x}+\num{\y})\,\si{\m}$ will give you correct spacing and a translated decimal separator (but it's not very convenient, of course). –  Jake Apr 28 '13 at 19:38
1  
@Bugbusters: Now you do =) –  Jake Apr 28 '13 at 19:42
2  
This does just look like a range: what is wrong with \SIrange{1.23}{4.56}{\metre}? –  Joseph Wright Apr 28 '13 at 19:56
1  
@JosephWright Physicists always have strange ideas about mathematical notation. ;-) The space isn't really necessary between a number and a unit: people have written $2a$ for centuries, after all. It's just a convention in the case a unit follows a number, to avoid ambiguities; what ambiguity can arise here? I'd say the space would be ambiguous, instead. –  egreg Apr 28 '13 at 20:13
1  
@Bugbusters Because you can set it up so that it works like you want the sum to work: \newcommand*{\SIsum}[4][]{\SIrange[range-phrase=+, range-units = brackets, #1]{#2}{#3}{#4}} –  Qrrbrbirlbel Apr 28 '13 at 20:24

1 Answer 1

up vote 9 down vote accepted

The siunitx package already handles products and quotients quite well, with a few auxiliary macros we can make + and - act as splitters for \num.

The correct inter-unit-product is taken from siunitx directly.

The second example shows one disadvantage of this approach: unitary signs need to be braced so that our own parser doesn’t see it. (Also, it misses some parentheses.) Though, I don’t see much use in them as minuses can simply replace the preceding +.

A better approach would be to use siunitx’/LaTeX 3’s already present facilities to parse the argument to \SI or \num similar to products and quotients (which may contradict their usage as \pm input literals).

The typesetting of the parentheses around all numbers is out-sourced to mathtools and its \DeclarePairedDelimiter macro. The new siunitx key any can be used to customize the optional argument/star to the delimiters (see examples).

And old version of the \SIany macro that takes one optional * (\SIany*…)/an optional argument in parenthesis (\SIany(\big)) which get forwarded to mathtools delimiter can be seen in revision 7 of this answer.

Code

\documentclass{article}
\usepackage{mathtools}
\usepackage[locale=DE]{siunitx}

\makeatletter
% copied from pgfutil-common.tex
\newif\ifqrr@in@
\def\qrr@in@#1#2{%
 \def\qrr@in@@##1#1##2##3\qrr@in@@{%
  \ifx\qrr@in@##2\qrr@in@false\else\qrr@in@true\fi}%
 \qrr@in@@#2#1\qrr@in@\qrr@in@@}
\def\qrr@in#1#2{\qrr@in@{#1}{#2}\ifqrr@in@\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi}
%

% Splitter
\def\parse@stop{\parse@stop}
\def\parse@numbers@split@plus#1+#2\parse@stop{\parse@numbers{#1}+\parse@numbers{#2}}
\def\parse@numbers@split@minus#1-#2\parse@stop{\parse@numbers{#1}-\parse@numbers{#2}}

%
\DeclarePairedDelimiter{\qrr@siunitx@p}{(}{)}

\ExplSyntaxOn
\def\qrr@siunitx@p@star{*}
\keys_define:nn { siunitx }{
    any .code:n = 
        \def\@tempa{#1}
        \ifx\qrr@siunitx@p@star\@tempa
            \def\qrr@siunitx@p@params{*}
        \else
            \expandafter\def\expandafter\qrr@siunitx@p@params
                \expandafter{\expandafter[\csname#1\endcsname]}
        \fi
}
\sisetup{any=}
\newcommand*\SIany[3][]{
    \begingroup
        \sisetup{#1}
        \expandafter\qrr@siunitx@p\qrr@siunitx@p@params{\parse@numbers{#2}}%
        \l__siunitx_unit_product_tl
        \si{#3}
    \endgroup}
\ExplSyntaxOff

% Parser
\def\parse@numbers#1{%
    \qrr@in+{#1}
        {\parse@numbers@split@plus#1\parse@stop}
        {%
            \qrr@in-{#1}
                {\parse@numbers@split@minus#1\parse@stop}
                {\num{#1}}
        }%
}

\makeatother
\begin{document}
$ \SIany{1.23 + 4.56 x 7.89 - 0.12 / 3.56}{\m} $

$ \SIany{1.23 + {-}4.56 x 7.89 - 0.12 / 3.56}{\m} $

\sisetup{quotient-mode=fraction}
$ \SIany{1 + 0.12 / 3.56}{\m} = \SIany[any=*]{1 + 0.12 / 3.56}{\m} = \SIany[any=big]{1 + 0.12 / 3.56}{\m} $
\end{document}

Output

enter image description here

share|improve this answer
    
(1) Maybe the line (\parse@numbers#2\parse@stop)% should be replaced by \left(\parse@numbers#2\parse@stop\right)%. (2) How do I change the spacing between the number and unit from \ to \,? –  Svend Tveskæg Apr 29 '13 at 0:52
    
@SvendTveskæg (1) Not really, as \left and \right) might produce too big delimiters. I added the functionality of \DeclarePairedDelimiter from the mathtools package. A \SIany* forwards the * to the delimiter, as well the optional () argument does. (The examples do hopefully make this clear.) [Note that siunitx has some form of bracket/parentheses functionality with lists and ranges, which could be extended to these delimiters, too.] (2) The default spacing is \, and can be set by the mentioned inter-unit-product option of siunitx. –  Qrrbrbirlbel Apr 29 '13 at 2:09
    
(1) Good point. (2) Hmmm. It just looks like \ to me, but it is nice if it isn't. –  Svend Tveskæg Apr 29 '13 at 2:13
    
@SvendTveskæg (1) I have introduced a new siunitx key instead of that weird first optional argument of \SIany: The any key! (2) Compare: \documentclass{article}\usepackage{siunitx}\begin{document}\ExplSyntaxOn\fbox{\‌​l__siunitx_unit_product_tl}\par\fbox{\,}\end{document}. It’s the same spacing as around +, - or \times (a thin one). –  Qrrbrbirlbel Apr 29 '13 at 2:39
    
This is really great. Good job! –  Svend Tveskæg Apr 29 '13 at 2:40

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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