27

I want to typeset big numbers with a separator (e.g a space or a ",") between hundreds and thousands, etc... For example 1 Million = 1 000 000.

I know the package siunitx which does it very well, but one must write \num{the big number}. Would it be possible, that this typeset automatically occurs for any number in a maths environment $ ...$, without being obliged to write explicitly \num ?

Torbjørn T.
  • 206,688
Loic Rosnay
  • 8,167
  • Well you could write \SI and include units.... >.> – Canageek Apr 02 '12 at 18:22
  • I'm surprised: there's no lua solution. (Yet?) – mbork Apr 02 '12 at 22:55
  • 1
    @mbrok: ConTeXt does parse digits when converting to MathML. For example $1234 x$ will be converted to <mnum> 123 </mnum> <...>x</...> (sorry don't remember MathML tags on top of my head. Of course the parser is written in Lua and, in principle, adding a output formatter for PDF output is easy. – Aditya May 30 '12 at 15:31
  • Thanks for this question, I was just wondering the same thing. Since I think @David Carlisle's advice is as wise as his code is impressive, and am not tempted to use that code, my two cents is that inputting \, separators manually is often easier than writing \num{}. – Nagel Apr 03 '14 at 10:31
  • See the posting Making large numbers readable by inserting thinspaces for visual grouping for a LuaLaTeX-based solution that (a) works in both text and math mode and (b) doesn't operates only on the integer portions and not on the decimal portions of numbers – Mico Oct 29 '15 at 21:25

2 Answers2

30

You really really really don't want to do this.

But if you did want to do it, then you could do this, but you just know it's bound to break something.

enter image description here

\documentclass{article}

\usepackage{comma}
\def\commaformtoken{\,}
\edef\mca{\the\mathcode`0\space}
\edef\mcb{\the\mathcode`1\space}
\edef\mcc{\the\mathcode`2\space}
\edef\mcd{\the\mathcode`3\space}
\edef\mce{\the\mathcode`4\space}
\edef\mcf{\the\mathcode`5\space}
\edef\mcg{\the\mathcode`6\space}
\edef\mch{\the\mathcode`7\space}
\edef\mci{\the\mathcode`8\space}
\edef\mcj{\the\mathcode`9\space}

\def\normaldigits{%
\mathcode`\0=\mca
\mathcode`\1=\mcb
\mathcode`\2=\mcc
\mathcode`\3=\mcd
\mathcode`\4=\mce
\mathcode`\5=\mcf
\mathcode`\6=\mcg
\mathcode`\7=\mch
\mathcode`\8=\mci
\mathcode`\9=\mcj
}

\newcount\hmmcnt
\makeatletter
\def\hmmdef#1{%
\bgroup\lccode`\~`#1\lowercase{\egroup
\count@\mathcode`~
\mathcode`~="8000
\edef~{%
\bgroup
\noexpand\normaldigits
\afterassignment\noexpand\hummcomma\hmmcnt#1}}}

\def\hummcomma{\@commaform\hmmcnt\egroup}

\def\activedigits{
\hmmdef0
\hmmdef1
\hmmdef2
\hmmdef3
\hmmdef4
\hmmdef5
\hmmdef6
\hmmdef7
\hmmdef8
\hmmdef9
}


\makeatother

\begin{document}

\activedigits
\[123456 = \frac{1234560}{10} \]
\normaldigits
\[123456 = \frac{1234560}{10} \]
\activedigits
\[123456 = \frac{1234560}{10} \]

\end{document}

siunitx update:

If you'd rather use siunitx rather than comma package to do the spacing then change the package loading, and change

\def\hummcomma{\@commaform\hmmcnt\egroup}

to

\def\hummcomma{\num{\the\hmmcnt}\egroup}

basic idea of code

to turn 123 into \num{123} the idea is fairly simple.

  1. give each digit an active definition so that, say, 1 is equivalent to \aftarassignment\helper\count@1

  2. TeX then starts to assign a number to \count@ so it gobbles up all following digits until it gets to a non-digit leaving the value in \count@ (and failing if that number is too big).

  3. The \afterassignment primitive then re-inserts the \helper token to expand, so this can now access the number from the count register as \the\count@ so \expandafter\num\expandafter{\the\count@} is the same as \num{123}

There is a slight problem in that the above description doesn't work, as you don't know which digit will be first, so you have to make all digits have mathcode "8000 and all have active definitions. But they would still have those definitions when the digits were re-inserted by executing \the\count@ which would put you in an infinite loop. So the definition has to start a local group, within that group re-define each digit to typeset its normal \mathcode specified character, and then finally after applying the spacing command, end the group. The \mc? commands are the saved mathcodes for each of the digits, and \hmmdef sets up the digit specified in its argument to have the right mathcode and active definition. \hmmcomma is the helper token inserted by \aftergroup that actually does the spacing of every third digit, using siunitx or comma packages.

update changed the grouping to use \bgroup rather than \begingroup as the latter does not work with x^2 you have to use the official LaTeX syntax x^{2}.

David Carlisle
  • 757,742
  • Wow! You need to explain this:) – yannisl Apr 02 '12 at 20:03
  • and by the way ... why should i really really really do NOT want to do this ? – Loic Rosnay Apr 02 '12 at 20:43
  • 19
    reasons for not doing this: either (a) something will go wrong or, worse, (b) it will work and you'll like using it then 20 years later something will go wrong and you'll expect me to remember how to fix it. – David Carlisle Apr 02 '12 at 20:53
  • Just to throw a wrench in the works: Is it possible to modify the code to accept a minimum 5-digit integer before grouping occurs (similar to siunitx's group-minimum-digits)? – Werner Apr 03 '12 at 01:18
  • @DavidCarlisle : too late, i implemented your code and sold the software with your name for online-support ;) – Loic Rosnay Apr 03 '12 at 06:26
  • @Werner, that should just work, as the integer sequence is passed to \num so it will group or not according to its usual definition. Note what doesn't work is 00123 (leading zeros stripped) and 1234.1234 decimal groups should group from the left not from the right and 1234.0001 zeros stripped which is really bad – David Carlisle Apr 03 '12 at 06:41
  • @DavidCarlisle Couldn't the last problem you mension be solved by something like \@ifnextchar.\@addtonum\relax by the end of something and defining \@addtonum macro to look for zeros, add them to \num argument and then parse again the remaining digits? – yo' Apr 03 '12 at 09:15
  • @tohecz simpler probably would just be to always put a 1 in front before collecting and then gobble the first token before splitting the groups. siunitx \num would group decimals correctly if it were passed them, comma.sty does not handle that it only does integers – David Carlisle Apr 03 '12 at 10:35
  • It does not work with numbers in tikz-nodes. Any workaround ? – Loic Rosnay May 30 '12 at 10:38
  • @nicolasroy I shall forward your question to the chat channel where my more tikz oriented colleagues lurk – David Carlisle May 30 '12 at 11:04
  • @nicolasroy It surely is a good follow-up question. – egreg May 30 '12 at 11:08
  • @nicolasroy Works for me. Can you expand on what you mean by "it does not work"? – Andrew Stacey May 30 '12 at 11:19
  • @AndrewStacey: take David's code and simply put \begin{tikzpicture}\node {600000};\end{tikzpicture} and i see no thousand separator. – Loic Rosnay May 30 '12 at 11:38
  • @nicolasroy The code only works for numbers in maths mode. The number there isn't in maths mode. – Andrew Stacey May 30 '12 at 11:39
  • I assume \node{$600000$} would be better? – David Carlisle May 30 '12 at 11:40
  • @DavidCarlisle Surely \node{\(6000000\)}? – Andrew Stacey May 30 '12 at 11:41
  • yes, of course. My mistake. – Loic Rosnay May 30 '12 at 13:36
  • is there an easy way to switch off/on this feature, if there is a sensible part of the code, where this happened not to work ? – Loic Rosnay May 30 '12 at 13:37
  • put the 10 lines that look like \mathcode\noexpand\0=\mca into a macro called something like\restoredigits` then you can call \restoredigits at any point and they will go back to normal for the rest of that scope – David Carlisle May 30 '12 at 13:57
  • but if possible , i would like to be able to switch it on later on... – Loic Rosnay May 30 '12 at 14:42
  • well either use the natural grouping to restore or stick the 10 lines that look like \hmmdef0 into a macro \activedigits and use that to switch things on – David Carlisle May 30 '12 at 14:55
  • Putting the 10 lines like \mathcode'\noexpand\0=\mca in a macro \restoredigits and involving this macro produces an error : A one-character control sequence belongs after a mark. So I'm essentially inserting \0 here. ! Undefined control sequence.` – Loic Rosnay May 30 '12 at 15:02
  • sorry you need to shuffle the position of \noexpand I updated the answer showing the code on off then on again – David Carlisle May 30 '12 at 15:25
  • Why a number 12345678901 produces an error "number too big", though the same number used directly with \@commaform does not ? – Loic Rosnay Sep 11 '12 at 09:15
  • @nicolasroy commaform just acts on the digits as a sequence of tokens sticking a comma every three, so has no real limit, but here a count register is used to collect the number so you are limited to the size of TeX's count type. – David Carlisle Sep 11 '12 at 09:39
  • @David: Ok, thanks. And could I easily bypass this restriction ? – Loic Rosnay Sep 11 '12 at 12:55
  • @nicolasroy, no, you'd have to rewrite the code not to use \afterassignment to grab the number and instead move along token by token checking for digits, which must be possible but would be a completely different answer – David Carlisle Sep 11 '12 at 13:02
  • Very interesting. But here is how it breaks (with decimal places): \activedigits [0.123456 = \frac{1.23456}{10} ] \normaldigits [0.123456 = \frac{1.23456}{10} ] – Eugene Dec 15 '14 at 02:53
7

No it is not possible to automate this in LaTeX. Many people including Knuth will disagree with you using thousands separators in math environments. (See Should one use thousands separators in equations?).

Edit

As David just showed it is possible to automate it.

yannisl
  • 117,160
  • In most cases it is probably better to use scientific notation or a larger unit (km instead of m for example), unless you need all the digits. – Canageek Apr 02 '12 at 18:23
  • 1
    @Canageek Sure it is better if is applicable but sometimes, especially in some expansions you might want to show discrete number coefficients. – yannisl Apr 02 '12 at 18:25
  • 4
    @YiannisLazarides, not sensible, but never say not possible, (see other answer:-) – David Carlisle Apr 02 '12 at 19:56
  • If you have numbers big enough to need thousands separators, it isn't maths, it's arithmetic. :) – Brent.Longborough May 30 '12 at 12:48
  • 1
    @Brent.Longborough Possibly, but they keep on popping up in papers using polynomials. When I was in high school maths was divided into three subjects for some years arithmetic, algebra and geometry:) – yannisl May 30 '12 at 12:52