% This is nrrange.sty, a LaTeX package.
% Christopher von B\"ulow, 2010.10.06

% Contains an algorithm to print out number ranges (aka "inclusive" or
% "continuing numbers"), e.g. page ranges, in abbreviated form,
% as suggested by various English style manuals.

% My names for various abbreviation conventions/styles:
% - "Oxford": The Oxford Guide to Style (2002, p. 169),
% - "Chicago": The Chicago Manual of Style (15th edn 2003, p. 396),
% - "MLA": MLA Style Manual and Guide to Scholarly Publishing
%     (2nd edn 1998, p. 118; MLA: Modern Language Association),
% - "Cenglish": my style for English texts (almost Oxford),
% - "Cgerman": my style for German texts,
% - "shortest": leave out every redundant digit in the 2nd number
%     (one might also call this "minimal"),
% - "full": leave out nothing, i.e. write out the 2nd number in full
%     (could also be called "longest", "maximal" or "trivial").
% These names should one day become alternative OPTIONS for the
% nrrange package.

% Which abbreviation convention is to be used depends on the style
% manual you consult, or on the house style of your publisher.
% One abbreviation convention would be the following, my hybrid between
% Oxford and Chicago:
%         \numberrange{604}{609} -> "604--9" instead of "604--609",
% whereas \numberrange{600}{609} -> "600--609" (Chicago, not Oxford)
%  [Oxf.: \numberrange{600}{609} -> "600--9"];
%         \numberrange{623}{628} -> "623--8" (Oxford, not Chicago)
% [Chic.: \numberrange{623}{628} -> "623--28"],
% whereas \numberrange{613}{618} -> "613--18" (both Oxf. and Chic.).

% I haven't seen any rationales for the conventions suggested by the
% different style manuals, so I made up one of my own. The abbreviation
% used should facilitate reading by leaving out redundant information,
% as long as this doesn't confuse the reader. So, imagine your
% (unabbreviated) number range as it would be spoken, e.g. "604--609" as
% "[from] six hundred [and] four to six hundred [and] nine". In the
% reader's mind this is digested (I suppose) as "in the 600's, go from 4
% to 9", which implies that you don't need to repeat the "600's"
% information in the 2nd number word. In short, with the omissible part
% put in parentheses:
%   "six hundred [and] four -- (six hundred [and]) nine".
% The range "600--609", on the other hand, is spoken as "[from]
% six hundred to six hundred [and] nine" and NOT digested (I believe) as
% "in the 600's, go from 0 to 9", because the zero is not spoken. So,
% if you omit the "six hundred", it sounds like "GO DOWN from 600 to 9",
% or like it might be a reference to a figure/table 9 on p. 600. In
% other words, "600--609" is NOT to be understood as
%   "six hundred -- (six hundred [and]) nine"
% (i.e. the part in parentheses is NOT omissible), because there is no
% expression on the left-hand side (no "zero") that would correspond to
% the "nine" on the right-hand side. So you should repeat the "600's"
% information: "600--609".
% Similarly with the two ranges "623--628" and "613--618": The former is
% of the form
%   "six hundred twenty-three -- (six hundred twenty-) eight",
% where you can omit the "620"-part, somewhat like in "speakers of
% English and (speakers of) German" or in "bicycle-(riders) and
% tricycle-riders". The range "613--618", on the other hand, is NOT to
% be understood as
%   "six hundred thirteen -- (six hundred) four (teen)",
% because the part that is, strictly, redundant ("61x") does not form
% a continuous phrase. (In Japanese, it would; number words there go
% something like "six-hundred ten three to six-hundred ten four", like
% for 20's, 30's etc. in English.)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\RequirePackage{ifthen,calc,refcount}

% Some number variables for later use:
\newcounter{power@fTen}% The power of 10 that corresponds
  % to the position of the digit we are currently investigating;
  % thus 100 is the power of 10 that, in 789, corresponds to the
  % position of digit 7, because there the "7" means "7 times 100".
\newcounter{firstdigit@fm}% To memorize the first digit of m,
\newcounter{firstdigit@fn}%   resp. of n, after having calculated them.
\newcounter{firstdigit@fmfollowedbyzeroes}
\newcounter{higherp@wer}
\newcounter{new@m}
\newcounter{new@n}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\pagerange}[2]% Takes two \label-keys as arguments.
 {\refused{#1}\refused{#2}% In case a reference is (as yet) undefined.
  % Apply \numberrange to the numbers \pageref delivers for the keys:
  pp.\ \numberrange{\getpagerefnumber{#1}}{\getpagerefnumber{#2}}%
 }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\numberrange}[2]
 {% We presuppose that the two arguments, #1 =: M and #2 =: N, are
  % numbers. If M isn't less than N, we stop right there:
  \ifthenelse{\NOT #1 < #2}
    {#1--#2% An additional warning sign in the document would be nice.
     \typeout{The arguments for the numberrange command are wrong:
              either #1 and #2 are not both (just) numbers,
              or #1 is not less than #2.}%
    }
     % In the else-part, M < N is now assured.
    {% [1]
     % Write down M and the dash:
       #1--%
     % How many digits does M have?  Calculate the power of 10 that
     % corresponds to the first ("highest") digit of M!
     % M is certainly greater-or-equal 10^0 (= 1):
       \setcounter{power@fTen}{1}%
     % In the following \whiledo-loop, power@fTen is certainly always
     % less-or-equal M.  So we multiply power@fTen with 10,
     % obtaining higherp@wer, and try out higherp@wer as the new
     % power@fTen, until we have found the greatest power@fTen
     % less-or-equal M, i.e. the one such that M < higherp@wer.
       \setcounter{higherp@wer}{\value{power@fTen}*10}%
       \whiledo{\NOT #1 < \value{higherp@wer}}
         {\setcounter{power@fTen}{\value{higherp@wer}}%
          \setcounter{higherp@wer}{\value{power@fTen}*10}%
         }%
     % Now M is still greater-or-equal power@fTen, but less than
     % higherp@wer.  The following command then works out recursively
     % which part of N to write down.
       \write@llorlosetheleadingdigit{#1}{#2}%
    }% [1]
 }% End of \newcommand{\numberrange}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\newcommand{\write@llorlosetheleadingdigit}[2]% Depending on what #1
  % (=: m) is:  either write all of #2 =: n and stop;  or lose the first
  % digit of m and of n, and then repeat that process with the new,
  % shortened m and n.
 {% If n has more digits than m (i.e. is greater-or-equal higherp@wer)
  % we must write it out in full:
    \ifthenelse{\NOT #2 < \value{higherp@wer}}
      {% Write down n:
         #2%
      }
       % Otherwise n has the same number of digits as m (i.e. both are
       % greater-or-equal power@fTen but less than higherp@wer)
       % and we have to check various criteria to decide whether we
       % leave out n's first digit:
      {% [2]
       % Compare the first digits of m and n. If the first digit
       % of n is greater than that of m, it (and the rest of n) must
       % be written down:
         \setcounter{firstdigit@fm}{#1/\value{power@fTen}}%
         \setcounter{firstdigit@fn}{#2/\value{power@fTen}}%
         \ifthenelse{\value{firstdigit@fn} > \value{firstdigit@fm}}
           {% Write down n:
              #2%
           }
            % Else m and n have the same first digit, and whether
            % it must be written down depends on m's following digits:
           {% [3]
% The following criterion depends on the style!
% Chicago, my style and my German style have it;
% Oxford, MLA and minimal do not.
            % If m's first digit is followed by just a row of zeroes,
            % n must again be written out in full:
             \setcounter{firstdigit@fmfollowedbyzeroes}
                {\value{firstdigit@fm} * \value{power@fTen}}%
                 % (dividing m by power@fTen to obtain
                 %  firstdigit@fm has cut off the following digits;
                 %  then multiplying again with power@fTen
                 %  replaces them with a row of zeroes)
              \ifthenelse
                {#1 = \value{firstdigit@fmfollowedbyzeroes}}
                {% Write down n:
                   #2%
                }
                 % If, however, m is not 1*power@fTen, 2*power@fTen,
                 % ... or 9*power@fTen, then nothing stands in the way
                 % of leaving out n's first digit --
                 % except if that's n's ONLY digit,
% The following criterion is style-dependent!
                 % or if m (and thus also n) are "teens" like 13
                 % (or 10, or 11, or 12) and 17:
                {% [4]
                 % If power@fTen = 1,  % This is universal.
% The following isn't:
% Oxford and my style have it;
% minimal doesn't;
% and Chicago, MLA and my German style have more general rules.
% If power@fTen = 10, then write down BOTH of n's digits IF --
% -- Chicago/my German style: firstdigit@fm is in 1, 2, ..., 9;
% -- MLA: firstdigit@fm is in 0, 1, ..., 9 (i.e. always).
                 % OR power@fTen = 10 and m's first digit is 1,
                 % write out n:
                   \ifthenelse
                     {\value{power@fTen} = 1  \OR
                      \( \value{power@fTen} = 10  \AND  \value{firstdigit@fm} = 1 \)
                     }
                     {% Write down n:
                        #2%
                     }
                      % Else we can indeed leave out n's first digit.
                      % Now we have to ask analogous questions
                      % for the next digit, and so on:
                     {% [5]
                      \setcounter{new@m}{#1 - \value{firstdigit@fmfollowedbyzeroes}}%
                      \setcounter{new@n}{#2 - \value{firstdigit@fn} * \value{power@fTen}}%
                      \setcounter{higherp@wer}{\value{power@fTen}}%
                      \setcounter{power@fTen}{\value{power@fTen}/10}%
                      \write@llorlosetheleadingdigit{\arabic{new@m}}{\arabic{new@n}}%
                     }% [5]
                }% [4]
           }% [3]
      }% [2]
 }% End of \newcommand{\write@llorlosetheleadingdigit}
