Monday, April 5, 2010

Ordinal numbers

Ever want TeX to write an ordinal number correctly? There are a number of fairly complicated solutions on the web so I decided to write one that was easy to read and follow.
\def\ord#1{\begingroup
        \count@=#1\relax
        \the\count@
        \ifnum\count@>99
                \count0\count@
                \divide\count0 by100
                \multiply\count0 by100
                \advance\count@ by-\count0
        \fi
        \ifnum\count@>19
                \count0\count@
                \divide\count0 by10
                \multiply\count0 by10
                \advance\count@ by-\count0
        \fi
        \ifcase\count@ th%
                \or st%
                \or nd%
                \or rd%
                \else th%
        \fi
\endgroup}
Note that this requires @ to be a letter, so \makeatletter or \catcode`@11. The first \ifnum block mods out by 100 since that plays no role in determining the ordinal suffix. The next block mods out by 10 if \count@ is at least 20. This is because 10th through 19th use th but 20th through 99th only examine the ones digit. Lastly, if the one's digit is 0, 4, 5, 6, 7, 8, or 9, (or the tens digit is 1) use th, otherwise use st, nd, or rd as appropriate. Using old-style superscripts requires a trivial modification.

Default units

In the previous post, I mentioned that when changing font sizes, there is a neat hack that allows the font size macros to have default units. That is the subject of today's brief post. The setup is you want to devise a macro that sets a dimension register to a particular value. For example,
\newdimen\foo
\newcommand*\set[1]{\foo#1\relax}
Now if you know that most of the time the units used are in points—as is the case with the font size macros—you can add the units in the \set macro,
\newcommand*\set[1]{\foo#1 pt\relax}
This works unless you want to sometimes specify your own units. At this point, we can use the \afterassignment primitive and a macro with a delimited argument to scoop up the default units. This is exactly what the \@defaultunits macro does.
\def\@defaultunits{\afterassignment\remove@to@nnil}
\def\remove@to@nill#1\@nnil{}
We can change our \set macro to be
\newcommand*\set[1]{\@defaultunits\foo#1 pt\relax\@nnil}
Let's take a look to see what this does in two cases.
\set{10}
\set{10ex}
In the first case, \set expands which causes \@defaultunits to expand and the \afterassignment is set to \remove@to@nnil. Next, \foo 10 pt\relax causes the dimension register specified by \foo to be set to 10pt and now \remove@to@nnil expands which gobbles up the \@nnil and \set is finished.

In the second case, \@defaultunits expands and \afterassignment is set as before. This time, \foo 10ex causes the dimension register to be set to 10ex and \remove@to@nnil expands which gobbles the pt\relax\@nnil and \set is finished. The \relax is more crucial if the register being set is a skip register rather than a dimension register since the pt by itself is not sufficient for the assignment but the \relax causes TeX to stop looking for more skip specification tokens. Less brief than I intended.

Wednesday, March 31, 2010

Global font size changes

The question of how to change the font size for a row in a table came up recently. It's tricky since each cell in a tabular is in its own group. My thought was a global font size change for the row that needed it and then a global change back. Since commands like \tiny actually perform many different assignments, \global\tiny does not do what we need. TeX provides an \afterassignment primitive that takes the next token and places it after the next assignment. For example,
\afterassignment\TeX
\count255=3
\the\count255
acts like
\count255=3
\TeX
\the\count255
The basic idea is to use \afterassignment with a helper macro which uses \afterassignment and \global.
\def\helper{\afterassignment\helper\global}
This doesn't quite work since there's no good way to stop it. Modifying it slightly to make it conditional allows us to turn it off:
\newif\ifhelper
\def\helper{\ifhelper\afterassignment\helper\global\fi}
Two more snags remain. First, the font size changing macros actually make use of \afterassignment to allow default units (a neat trick in its own right) and \global\afterassignment is an error so we need to reimplement it. Similarly, vrule is used and \global \vrule is an error so we have to work around that. The final snag is that the first time TeX executes one of the font size commands like \tiny it performs extra work and that extra work doesn't play so nicely with our hack. The workaround for this is to simply execute the font size changing macro first. The complete code looks like this.
\newif\ifhelper
\makeatletter
\def\unithelper#1\@nnil{\global\helpertrue\helper}
\def\helper{\ifhelper\afterassignment\helper\global\fi}
\newcommand*\globalfontsize[1]{%
\begingroup
       #1%
       \def\@defaultunits{\helperfalse\afterassignment\unithelper\global}%
       \let\realvrule\vrule
       \def\vrule{\helperfalse\global\helpertrue\afterassignment\helper\realvrule}%
       \global\helpertrue
       \helper#1%
       \helperfalse
\endgroup}
\makeatother
\newcommand*\globaltiny{\globalfontsize\tiny}
\newcommand*\globalnormalsize{\globalfontsize\normalsize}
Now we can use \globaltiny and \globalnormalsize in the table to change the font for the whole row.

Wednesday, November 25, 2009

Spaces in TeX, part II

Finally back. A while back, I covered spaces in TeX and why they don't always appear. Today's much shorter post will cover a few additional places spaces do not appear. The most obvious place one might expect a space—a vertical one this time—comes from consecutive new lines. The thought goes, if one blank line produces a newline, then surely two blank lines will produce two newlines. This reasoning is incorrect. From before, recall that TeX produces \par tokens when it sees end of line characters in state N. What TeX does with a \par token depends on its mode. There are six different modes, vertical, internal vertical, horizontal, restricted horizontal, math, and display math, but to simplify matters, let's only consider vertical and horizontal. (The internal vertical and restricted horizontal are similar enough to vertical and horizontal for our purpose.) TeX starts in vertical mode and then transitions to horizontal mode (and does things like indentation) to typeset a paragraph. When it sees a \par token, it transitions back to vertical mode. While in vertical mode, \par tokens are ignored. Thus, while two blank lines produce two \par tokens, the first causes TeX to return to vertical mode and the second is ignored. The TeX primitive \vskip or the LaTeX macro \vspace can be used in vertical mode to get additional space, as desired. There are a few other places where TeX ignores spaces, but those are fairly rarely encounted, so I'll only briefly mention them. When TeX expects to see a number, the number can be given as a sequence of digits followed by an optional space. There's actually one place where the optional space is fairly important and that is changing the category code of a character and then using that character immediately. Even less frequently encountered, at least by me, is starting a paragraph with an \hbox causes the paragraph to not be indented. Use of the LaTeX macro \mbox solves this problem, as does starting the paragraph with \indent or \noindent, as desired. And I think that wraps up all I have to say about spaces in TeX.

Friday, October 16, 2009

A quick interlude into fonts

Dealing with fonts in LaTeX is one of the hardest aspects of using it. Fortunately, if one does not want to use Knuth's Computer Modern fonts, there is a very simple way to change font families. Full details are here, but for a publication that requires a Times roman typeface, one should use
\usepackage{mathptmx}
\usepackage[scaled=.92]{helvet}
\usepackage{courier}
which causes the roman and math fonts to be Times, the sans serif fonts to be in Helvetica—scaled so that it matches the other fonts better—and courier for the typewriter family. These three look nice together. In addition, output font encoding can be changed to T1 with
\usepackage[T1]{fontenc}
which is recommended. For more details see the above link

Wednesday, October 14, 2009

Spaces in TeX

Spaces appear all over .tex files but only some of them appear as actual spaces in the output. To understand this, we first need to understand how TeX reads lines of input.

When reading input, TeX is in one of three states: state N is when TeX is at the beginning of a new line; state M is when TeX is in the middle of the line; and state S is when TeX is skipping spaces. TeX will discard space characters it sees in any state except for M. Basically, TeX starts in state N and on the first non space character (actually, it's slightly more complicated, but for for the purposes of this post, just consider tabs as spaces), it transitions into state M. While in state M, each character that is read is turned into a token except that control sequences are turned into a single token (again, it's more complicated than that, but this will suffice). Once a space is encountered, a space token is created and TeX enters state S. Again, a nonspace character brings TeX into state M. As an example, consider the line of input:
Hello      \TeX!
TeX begins in state N and then upon reading the H transitions into state M and produces an H token. Then e, l, l, and o tokens are produced in turn.

Upon reading the first space, TeX produces a space token and then enters state S. The rest of the spaces up to the \ are ignored. Once TeX reads the \, it will scan the rest of the control sequence and produce a single \TeX token. Finally, TeX produces a ! token. I haven't said what state TeX enters when it scan a control sequence. The answer depends on what type of control sequence it is. If the first character after the \ is not a letter, for example if it's a symbol like @ or #, then TeX produces a token consisting of the control symbol. (For example, the token \@ or \#.) In this case, TeX enters (or remains in) state M. If instead, the first character after the \ is a letter, then TeX reads a control word consisting of the \ and all following letters. TeX then enters state S. This explains why TeX ignores spaces after control words like \TeX or \bf. So in the example above, since \TeX is a control word, TeX will enter state S after reading that control word and then immediately enter state M when it reads the !.

Before we can move on, there are two points I skipped. Before TeX starts processing a line of input, it deletes all space characters at the right of the line and inserts a carriage return character which, by default, is the end of line character. So to conclude the discussion of a single line, we need to know what happens with comment characters and end of line characters. For a comment character, all information on the rest of the input line is thrown away and TeX starts on the next line of input in state N. For an end of line character, TeX throws away all remaining input on the line (just like a comment) and then does one of three things. If TeX is in state N, then it produces a \par token. If TeX is in state M, it produces a space token. If TeX is in state S, it ignores the end of line character.

Let's consider the implications of the handling of the end of line character. In state N, it produces a new paragraph which is why entering a blank line in your TeX source gives you a new paragraph. In State M, it produces a space which is why we can sprinkle newlines (almost) anywhere we like in our source and we get spaces. If spaces are being skipped, for example after a control word (but not a control symbol!), then the end of line does nothing. [Okay, one final lie above, after a control symbol consisting of \ and a space, TeX enters state S. This is so that \ followed by two spaces does not produce two space tokens.] To summarize, when TeX reads a line of input, it
  1. removes trailing spaces and adds a carriage return,
  2. enters state N,
  3. reads characters, creating tokens and changing states as described above until it,
  4. reaches the end of line character which is either turned into a \par token, a space token, or ignored, depending on the current state.

This is not the end of the story as there are situations where TeX ignores space tokens and \par tokens a.k.a, "why don't I get more blank lines when I enter more blank lines in my source?" However, this post is long enough, so I'll put that off for now and discuss modes, next time.

Monday, October 5, 2009

Defining new math operators

Defining a new math operator that behaves similar to \sin or \lim is very easy to do using the amsmath package. It provides a \DeclareMathOperator macro that works in the preamble to declare a new operator. It also contains a starred version that behaves similar to \lim with respect to subscripts. For example:
\DeclareMathOperator\arcsec{arcsec}
\DeclareMathOperator*\Lim{Lim}
In addition, \operatorname or \operatorname* can be used for one-time uses that don't warrant defining a new control sequence for the operator name. These are better than using \mathrm to define operator names if for no other reason than spacing is handled correctly in the presence or absence of parentheses.