From: Phil Hirschhorn <PHIRSCHHORN@LUCY.WELLESLEY.EDU>
Newsgroups: comp.text.tex
Subject: Re: Two questions
Date: Mon, 25 Jan 1993 22:59 EST
Organization: Info-Tex<==>Comp.Text.Tex Gateway
X-Gateway-Source-Info: Mailing List

This is a solution to one of Michael Barr's questions.  \commas is a
macro that takes one argument, which can be either a number or a
counter, and prints that argument with commas separating groups of
three digits.  Thus,  \commas{1234567} and

\newcounter\mycounter
\mycounter=1234567
\commas{\mycounter}

both produce 1,234,567.

The partial solutions posted so far take the approach of doing
arithmetic on the number to peel off the high order digit.  Here, we
just treat the number as a string of symbols, and peel them off one
at a time.

In outline:

Check to see if the argument is a number or a counter. In either
case, define \expanded so that it expands to the string of digits we
want to print.

Count the digits in the string, and store the result in \numdigits.

Reduce \numdigits mod 3 (i.e., find the remainder on dividing
\numdigits by 3).

Print the digits one at a time, using \numdigits to keep track of
when we should insert a comma.


We intentionally never assign the argument of \commas to a counter,
since the upper limit on the value of a counter in TeX is
2,147,483,647 = 2^{31}.  This is why we must use \ifcat to test the
catcode of 0 (a randomly chosen digit) against the catcode of the
argument.  Since the argument might be a string of digits (only the
first of which would be eaten by \ifcat), we use \biggobble to clean
up the mess left behind by the test.

One other (possibly non-obvious) point below is that we usually keep
\numdigits between 1 and 3, but when we start printing we have
\numdigits equal to either 0, 1, or 2.  This is to avoid printing a
comma in front of a number like 123; We only print a comma when
there are digits remaining and \numdigits=3.  When we go to print the
first digit, \numdigits is at most 2.

There's no error checking here at all; A bad argument will probably
make the whole thing blow up in your face.  TeX isn't C, and I find
it hard enough to get things to work even with good input.

Phil Hirschhorn
----------------------------------------------------------------------
\def\gobble#1{}
\def\biggobble#1\relax{}
\newcount\numdigits

\def\commas#1{\expandafter\biggobble\ifcat0#1%
                 % the argument is a digit string
                 \relax\def\expanded{#1}%
              \else
                 % the argument is a counter
                 \relax\edef\expanded{\the#1}%
              \fi
              \countdigits\expanded
              \reducemodthree\numdigits
              \expandafter\dodigit\expanded\relax}

\def\dodigit#1{\ifx#1\relax
                  \let\next=\relax
               \else
                  \ifnum\numdigits=3
                     ,#1%
                  \else
                     #1%
                  \fi
                  \advance\numdigits by -1
                  \ifnum\numdigits<1
                     \advance\numdigits by3
                  \fi
                  \let\next=\dodigit
               \fi
               \next}

\def\reducemodthree#1{\ifnum#1>2
                          \advance#1 by -3
                          \let\next=\reducemodthree
                      \else
                          \let\next=\gobble
                      \fi
                      \next#1}

\def\countdigits#1{%   #1 is a string of digits, or a macro
                   %      that expands to a string of digits
		   \numdigits=0
                   \expandafter\countem#1\relax}

\def\countem#1{\ifx#1\relax
                  \let\next=\relax
               \else
                  \advance\numdigits by 1
                  \let\next=\countem
               \fi
               \next}