% \iffalse %% File: l3int.dtx Copyright (C) 1990-2008 LaTeX3 project %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this %% license or (at your option) any later version. The latest version %% of this license is in the file %% %% http://www.latex-project.org/lppl.txt %% %% This file is part of the ``expl3 bundle'' (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX Project Team. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} % %\fi \GetIdInfo$Id: l3int.dtx 738 2008-08-01 13:21:42Z morten $ {L3 Experimental Integer module} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass{l3doc} \begin{document} \DocInput{\filename.\filenameext} \end{document} % % \fi % % % \title{The \textsf{l3int} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Counters} % \author{\Team} % \date{\filedate} % \maketitle % % \section{Integers} % % \LaTeX3 maintains two type of integer registers for internal use. % One (associated with the name "num") for low level uses in the % allocation mechanism using macros only and "int": the one described % here. % % The "int" type uses the built-in counter registers of \TeX{} and is % therefore relatively fast compared to the "num" type and should be % preferred in all cases as there is little chance we should ever run % out of registers when being based on at least \eTeX. % % \subsection{Functions} % % \begin{function}{% % \int_new:N | % \int_new:c | % \int_new_l:N | % } % \begin{syntax} % "\int_new:N" % \end{syntax} % Globally defines to be a new variable of type "int" although % you can still choose if it should be a an "\l_" or "\g_" type. % There is no way to define constant counters with these functions. % The function "\int_new_l:N" defines locally only. % \begin{texnote} % "\int_new:N" is the equivalent to plain \TeX{}'s \tn{newcount}. % However, the internal register allocation is done differently. % \end{texnote} % \end{function} % % \begin{function}{% % \int_incr:N | % \int_incr:c | % \int_gincr:N | % \int_gincr:c | % } % \begin{syntax} % "\int_incr:N" % \end{syntax} % Increments by one. For global variables the global versions % should be used. % \end{function} % % \begin{function}{% % \int_decr:N | % \int_decr:c | % \int_gdecr:N | % \int_gdecr:c | % } % \begin{syntax} % "\int_decr:N" % \end{syntax} % Decrements by one. For global variables the global versions % should be used. % \end{function} % % \begin{function}{% % \int_set:Nn | % \int_set:cn | % \int_gset:Nn | % \int_gset:cn | % } % \begin{syntax} % "\int_set:Nn" "{" "}" % \end{syntax} % These functions will set the register to the % value. This value can contain simple calc-like expressions as % provided by \eTeX. % \end{function} % % % \begin{function}{% % \int_zero:N | % \int_zero:c | % \int_gzero:N | % \int_gzero:c | % } % \begin{syntax} % "\int_zero:N" % \end{syntax} % These functions sets the register to zero either locally % or globally. % \end{function} % % % \begin{function}{% % \int_add:Nn | % \int_add:cn | % \int_gadd:Nn | % \int_gadd:cn | % } % \begin{syntax} % "\int_add:Nn" "{" "}" % \end{syntax} % These functions will add to the register the value . If the second argument is a register too, the % surrounding braces can be left out. % \end{function} % % \begin{function}{% % \int_sub:Nn | % \int_sub:cn | % \int_gsub:Nn | % \int_gsub:cn | % } % \begin{syntax} % "\int_gsub:Nn" "{" "}" % \end{syntax} % These functions will subtract from the register the value % . If the second argument is a register too, the % surrounding braces can be left out. % \end{function} % % \begin{function}{% % \int_use:N | % \int_use:c | % } % \begin{syntax} % "\int_use:N" % \end{syntax} % This function returns the integer value kept in in a way % suitable for further processing. % \begin{texnote} % The function "\int_use:N" could be implemented directly as the \TeX{} % primitive "\tex_the:D" which is also responsible to produce the values for % other internal quantities. We have chosen to use individual functions % for counters, dimensions etc.\ to allow checks and to make the code % more self-explaining. % \end{texnote} % \end{function} % % \subsection{Formatting a counter value} % % \begin{function}{ % \int_to_arabic:n | % \int_to_alph:n | % \int_to_Alph:n | % \int_to_roman:n | % \int_to_Roman:n | % \int_to_symbol:n | % } % \begin{syntax} % "\int_to_alph:n" "{" "}" % "\int_to_alph:n" % \end{syntax} % If some or the the current value of a should be % displayed or typeset in a special ways (e.g., as uppercase roman % numerals) these function can be used. We need braces if the % argument is a simple , they can be omitted in case of a % . By default the letters produced by "\int_to_roman:n" and % "\int_to_Roman:n" have catcode~11. % % All functions are fully expandable and will therefore produce the % correct output when used inside of deferred writes, etc. In case the % number in an |alph| or |Alph| function is greater than the default % base number (26) it follows a simple conversion rule so that 27 is % turned into |aa|, 50 into |ax| and so on and so forth. These two % functions can be modified quite easily to take a different base % number and conversion rule so that other languages can be supported. % \begin{texnote} % These are more or less the internal \LaTeX2 functions \tn{@arabic}, % \tn{@alph}, \tn{Alph}, \tn{@roman}, \tn{@Roman}, and \tn{@fnsymbol} % except that "\int_to_symbol:n" is also allowed outside math mode. % \end{texnote} % \end{function} % % \subsubsection{Internal functions} % % \begin{function}{\int_to_roman:w} % \begin{syntax} % "\int_to_roman:w" \textit{or} % \end{syntax} % Converts to it lowercase roman representation. Note that % it produces a string of letters with catcode 12. % \begin{texnote} % This is the \TeX{} primitive \tn{romannumeral} renamed. % \end{texnote} % \end{function} % \begin{function}{ % \int_roman_lcuc_mapping:Nnn | % \int_to_roman_lcuc:NN | % } % \begin{syntax} % "\int_roman_lcuc_mapping:Nnn" "{""}" "{""}" % "\int_to_roman_lcuc:NN" % \end{syntax} % "\int_roman_lcuc_mapping:Nnn" specifies how the roman % numeral (i, v, x, l, c, d, or m) should be % interpreted when converting the number. is the lower case and % is the uppercase mapping. "\int_to_roman_lcuc:NN" is a % recursive function converting the roman numerals. % \end{function} % % % \begin{function}{ % \int_convert_number_with_rule:nnN | % \int_alph_default_conversion_rule:n | % \int_Alph_default_conversion_rule:n | % \int_symbol_math_conversion_rule:n | % \int_symbol_text_conversion_rule:n | % } % \begin{syntax} % "\int_convert_number_with_rule:nnN" "{""}" "{""}" % "\int_alph_default_conversion_rule:n" "{""}" % \end{syntax} % "\int_convert_number_with_rule:nnN" converts into letters, % symbols, whatever as defined by . denotes the base % number for the conversion. % \end{function} % % % % % % % \subsection{Variable and constants} % % \begin{variable}{% % \c_max_int | % } % Constant that denote the maximum value which can be stored in an % register. % \end{variable} % % % \begin{variable}{% % \l_tmpa_int | % \l_tmpb_int | % \l_tmpc_int | % \g_tmpa_int | % \g_tmpb_int | % } % Scratch register for immediate use. They are not used by conditionals % or predicate functions. % \end{variable} % % % \subsection{Testing and evaluating integer expressions} % % \begin{function}{% % \int_eval:n | % \int_div_truncate:nn | % \int_div_round:nn | % \int_mod:nn | % } % \begin{syntax} % "\int_eval:n" "{""}" \\ % "\int_div_truncate:n" "{""}" "{""}" \\ % "\int_mod:nn" "{""}" "{""}" % \end{syntax} % Evaluates the value of a integer expression so that % "\int_eval:n {3*5/4}" puts "4" back into the input stream. Note that % the results of divisions are rounded by the primitive operations. If % you want the result of a division to be truncated use % "\int_div_truncate:nn". "\int_div_round:nn" is added for % completeness. "\int_mod:nn" returns the remainder of a division. All % of these functions are expandable. % \begin{texnote} % "\int_eval:n" is the \eTeX primitive \tn{numexpr} turned into a function % taking an argument. % \end{texnote} % \end{function} % % \begin{function}{% % \int_compare:nNnTF | % \int_compare:nNnT | % \int_compare:nNnF | % } % \begin{syntax} % "\int_compare:nNnTF" "{""}" "{""}" % "{""}" "{""}" % \end{syntax} % These functions test two integer expressions against each other. They % are both evaluated by "\int_eval:n". Note that if both expressions % are normal integer variables as in % \begin{quote} % "\int_compare:nNnTF \l_temp_int < \c_zero {negative}{non-negative}" % \end{quote} % you can safely omit the braces. % \begin{texnote} % This is the \TeX{} primitive \tn{ifnum} turned into a function. % \end{texnote} % \end{function} % % \begin{function}{% % \int_compare_p:nNn | % } % \begin{syntax} % "\int_compare_p:nNn" "{""}" "{""}" % \end{syntax} % A predicate version of the above mentioned functions. % \end{function} % % \begin{function}{% % \int_max_of:nn | % \int_min_of:nn | % } % \begin{syntax} % "\int_max_of:nn" "{""}" "{""}" % \end{syntax} % Return the largest or smallest of two integer expressions. % \end{function} % % \begin{function}{% % \int_abs:n | % } % \begin{syntax} % "\int_abs:n" "{""}" % \end{syntax} % Return the numerical value of an integer expression. % \end{function} % % \begin{function}{% % \int_if_odd:nTF | % \int_if_odd_p:n | % } % \begin{syntax} % "\int_if_odd:nTF" "{""}" "{""}" "{""}" % \end{syntax} % These functions test if an integer expression is even or odd. We % also define a predicate version of it. % \begin{texnote} % This is the \TeX{} primitive \tn{ifodd} turned into a function. % \end{texnote} % \end{function} % % \begin{function}{% % \int_whiledo:nNnT | % \int_whiledo:nNnF | % \int_dowhile:nNnT | % \int_dowhile:nNnF | % } % \begin{syntax} % "\int_whiledo:nNnT" "{""}" % \end{syntax} % "\int_whiledo:nNnT" tests the integer expressions and if true performs % the body "T" until the test fails. "\int_dowhile:nNnT" is similar % but executes the body first and then performs the check, thus % ensuring that the body is executed at least once. The "F" versions % are similar but continue the loop as long as the test is false. They % could be omitted as it is just a matter of switching the arguments % in the test. % \end{function} % % \subsection{Conversion} % % \begin{function}{% % \int_convert_from_base_ten:nn | % } % \begin{syntax} % "\int_convert_from_base_ten:nn" "{""}""{""}" % \end{syntax} % Converts the base~10 number into its equivalent % representation written in base~. Expandable. % \end{function} % % % \begin{function}{% % \int_convert_to_base_ten:nn | % } % \begin{syntax} % "\int_convert_to_base_ten:nn" "{""}""{""}" % \end{syntax} % Converts the base~ number into its equivalent % representation written in base~10. can consist of digits % and ascii letters. Expandable. % \end{function} % % % \StopEventually{} % \subsection{The Implementation} % % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %\ProvidesExplPackage % {\filename}{\filedate}{\fileversion}{\filedescription} %\RequirePackage{l3num} %\RequirePackage{l3chk} %<*initex|package> % \end{macrocode} % % \begin{macro}{\int_to_roman:w} % \begin{macro}{\int_to_number:w} % \begin{macro}{\int_advance:w} % A new name for the primitives. % \begin{macrocode} \let_new:NN \int_to_roman:w \tex_romannumeral:D \let_new:NN \int_to_number:w \tex_number:D \let_new:NN \int_advance:w \tex_advance:D % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % Functions that support \LaTeX's user accessible counters should be % added here, too. But first the internal counters. % % \begin{macro}{\int_incr:N} % \begin{macro}{\int_decr:N} % \begin{macro}{\int_gincr:N} % \begin{macro}{\int_gdecr:N} % \begin{macro}{\int_incr:c} % \begin{macro}{\int_decr:c} % \begin{macro}{\int_gincr:c} % \begin{macro}{\int_gdecr:c} % Incrementing and decrementing of integer registers is done with % the following functions. % \begin{macrocode} \def_new:Npn \int_incr:N #1{\int_advance:w#1\c_one %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_decr:N #1{\int_advance:w#1\c_minus_one %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_gincr:N { % \end{macrocode} % We make sure that a local variable is not updated globally by % changing the internal test (i.e.\ |\chk_local_or_pref_global:N|) before % making the assignment. This is done by |\pref_global_chk:| which also % issues the necessary |\pref_global:D|. This is not very efficient, but % this code will be only included for debugging purposes. Using % |\pref_global:D| in front of the local function is better in the % production versions. % \begin{macrocode} %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_incr:N} \def_new:Npn \int_gdecr:N { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_decr:N} % \end{macrocode} % With the |\int_add:Nn| functions we can shorten the above code. % If this makes it too slow \ldots % \begin{macrocode} \def:Npn \int_incr:N #1{\int_add:Nn#1\c_one} \def:Npn \int_decr:N #1{\int_add:Nn#1\c_minus_one} \def:Npn \int_gincr:N #1{\int_gadd:Nn#1\c_one} \def:Npn \int_gdecr:N #1{\int_gadd:Nn#1\c_minus_one} \def:Npn \int_incr:c {\exp_args:Nc\int_incr:N} \def:Npn \int_decr:c {\exp_args:Nc\int_decr:N} \def:Npn \int_gincr:c {\exp_args:Nc\int_gincr:N} \def:Npn \int_gdecr:c {\exp_args:Nc\int_gdecr:N} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_new:N} % \begin{macro}{\int_new_l:N} % \begin{macro}{\int_new:c} % Allocation of a new internal counter is already done above. Here we define % the next likely variant. % \begin{macrocode} %<*initex> \alloc_setup_type:nnn {int} \c_eleven \c_max_register_num \def_new:Npn \int_new:N #1 {\alloc_reg:NnNN g {int} \tex_countdef:D#1} \def_new:Npn \int_new_l:N #1 {\alloc_reg:NnNN l {int} \tex_countdef:D#1} % %\let:NN \int_new:N \newcount% allocation better nick the LaTeX one... \def_new:Npn \int_new:c {\exp_args:Nc \int_new:N} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_set:Nn} % \begin{macro}{\int_set:cn} % \begin{macro}{\int_gset:Nn} % \begin{macro}{\int_gset:cn} % Setting counters is again something that I would like to make % uniform at the moment to get a better overview. % \begin{macrocode} \def_new:Npn \int_set:Nn #1#2{#1 \int_eval:w #2\int_eval_end: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_gset:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_set:Nn } \def_new:Npn \int_set:cn {\exp_args:Nc \int_set:Nn } \def_new:Npn \int_gset:cn {\exp_args:Nc \int_gset:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_zero:N} % \begin{macro}{\int_zero:c} % \begin{macro}{\int_gzero:N} % \begin{macro}{\int_gzero:c} % Functions that reset an \m{int} register to zero. % \begin{macrocode} \def_new:Npn \int_zero:N #1 {#1=\c_zero} \def_new:Npn \int_zero:c #1 {\exp_args:Nc \int_zero:N} \def_new:Npn \int_gzero:N #1 {\pref_global:D #1=\c_zero} \def_new:Npn \int_gzero:c {\exp_args:Nc \int_gzero:N} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_add:Nn} % \begin{macro}{\int_add:cn} % \begin{macro}{\int_gadd:Nn} % \begin{macro}{\int_gadd:cn} % \begin{macro}{\int_sub:Nn} % \begin{macro}{\int_sub:cn} % \begin{macro}{\int_gsub:Nn} % \begin{macro}{\int_gsub:cn} % Adding and substracting to and from a counter \ldots % We should think of using these functions % \begin{macrocode} \def_new:Npn \int_add:Nn #1#2{ % \end{macrocode} % We need to say |by| in case the first argument is a register % accessed by its number, e.g., |\count23|. Not that it should % ever happen but\dots % \begin{macrocode} \int_advance:w #1 by \int_eval:w #2\int_eval_end: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn\int_add:cn{\exp_args:Nc\int_add:Nn} \def_new:Npn \int_sub:Nn #1#2{ \int_advance:w #1-\int_eval:w #2\int_eval_end: %<*check> \chk_local_or_pref_global:N #1 % } \def_new:Npn \int_gadd:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_add:Nn } \def_new:Npn \int_gsub:Nn { %<*check> \pref_global_chk: % %<-check> \pref_global:D \int_sub:Nn } \def_new:Npn \int_gadd:cn{\exp_args:Nc\int_gadd:Nn} \def_new:Npn \int_sub:cn{\exp_args:Nc\int_sub:Nn} \def_new:Npn \int_gsub:cn{\exp_args:Nc\int_gsub:Nn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_use:N} % \begin{macro}{\int_use:c} % Here is how counters are accessed: % \begin{macrocode} \let_new:NN \int_use:N \tex_the:D \def_new:Npn \int_use:c #1{\int_use:N \cs:w#1\cs_end:} % \end{macrocode} % \end{macro} % \end{macro} % % % % % \begin{macro}{\int_to_arabic:n} % Nothing exciting here. % \begin{macrocode} \def_new:Npn \int_to_arabic:n #1{\int_to_number:w \int_eval:n{#1}} % \end{macrocode} % \end{macro} % % % % \begin{macro}{\int_roman_lcuc_mapping:Nnn} % Using \TeX's built-in feature for producing roman numerals has some % surprising features. One is the the characters resulting from % |\int_to_roman:w| have category code~12 so they may fail in % certain comparison tests. Therefore we use a mapping from the % character \TeX{} produces to the character we actually want which % will give us letters with category code~11.% % \begin{macrocode} \def_new:Npn \int_roman_lcuc_mapping:Nnn #1#2#3{ \def:cpn {int_to_lc_roman_#1:}{#2} \def:cpn {int_to_uc_roman_#1:}{#3} } % \end{macrocode} % \end{macro} % Here are the default mappings. I haven't found any examples of say % Turkish doing the mapping |i \i I| but at least there is a % possibility for it if needed. Note: I have now asked a Turkish % person and he tells me they do the |i I| mapping. % \begin{macrocode} \int_roman_lcuc_mapping:Nnn i i I \int_roman_lcuc_mapping:Nnn v v V \int_roman_lcuc_mapping:Nnn x x X \int_roman_lcuc_mapping:Nnn l l L \int_roman_lcuc_mapping:Nnn c c C \int_roman_lcuc_mapping:Nnn d d D \int_roman_lcuc_mapping:Nnn m m M % \end{macrocode} % For the delimiter we cheat and let it gobble its arguments instead. % \begin{macrocode} \int_roman_lcuc_mapping:Nnn Q \use_none:nn \use_none:nn % \end{macrocode} % % \begin{macro}{\int_to_roman:n} % \begin{macro}{\int_to_Roman:n} % \begin{macro}{\int_to_roman_lcuc:NN} % The commands for producing the lower and upper case roman numerals % run a loop on one character at a time and also carries some % information for upper or lower case with it. We put it through % |\int_eval:n| first which is safer and more flexible. % \begin{macrocode} \def_new:Npn \int_to_roman:n #1 { \exp_after:NN \int_to_roman_lcuc:NN \exp_after:NN l \int_to_roman:w \int_eval:n {#1} Q } \def_new:Npn \int_to_Roman:n #1 { \exp_after:NN \int_to_roman_lcuc:NN \exp_after:NN u \int_to_roman:w \int_eval:n {#1} Q } \def_new:Npn \int_to_roman_lcuc:NN #1#2{ \cs_use:c {int_to_#1c_roman_#2:} \int_to_roman_lcuc:NN #1 } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % % \begin{macro}{\int_convert_number_with_rule:nnN} % This is our major workhorse for conversions. |#1| is the number we % want converted, |#2| is the base number, and |#3| is the function % converting the number. This function expects to receive a % non-negative integer and as such is ideal for something using % |\if_case:w| internally. % % The basic example is this: We want to convert the number 50 (|#1|) % into an alphabetic equivalent |ax|. For the English language our % list contains 26 elements so this is our argument |#2| while the % function |#3| just turns |1| into |a|, |2| into |b|, etc. Hence our % goal is to turn 50 into the sequence |#3{1}#1{24}| so what we do is % to first divide 50 by 26 and truncating the result returning 1. % Then before we execute this we call the function again but this time % on the result of the remainder of the division. This goes on until % the remainder is less than or equal to the base number where we just % call the function |#3| directly on the number. % % We do a little pre-expansion of the arguments below as they % otherwise have a tendency to grow quite large. % \begin{macrocode} \def:Npn \int_convert_number_with_rule:nnN #1#2#3{ \int_compare:nNnTF {#1}>{#2} { \exp_args:No \int_convert_number_with_rule:nnN { \int_use:N\int_div_truncate:nn {#1-1}{#2} }{#2} #3 % \end{macrocode} % Note that we have to nudge our modulus function so it won't % return~$0$ as that wouldn't work with |\if_case:w| when that % expects a positive number to produce a letter. % \begin{macrocode} \exp_args:No #3 { \int_use:N\int_eval:n{1+\int_mod:nn {#1-1}{#2}} } } { \exp_args:No #3{ \int_use:N\int_eval:n{#1} } } } % \end{macrocode} % As can be seen it is even simpler to convert to number systems % that contain 0, since then we don't have to add or subtract 1 % here and there. % \end{macro} % % \begin{macro}{\int_alph_default_conversion_rule:n} % \begin{macro}{\int_Alph_default_conversion_rule:n} % Now we just set up a default conversion rule. Ideally every language % should have one such rule, as say in Danish there are 29 letters in % the alphabet. % \begin{macrocode} \def_new:Npn \int_alph_default_conversion_rule:n #1{ \if_case:w #1 \or: a\or: b\or: c\or: d\or: e\or: f \or: g\or: h\or: i\or: j\or: k\or: l \or: m\or: n\or: o\or: p\or: q\or: r \or: s\or: t\or: u\or: v\or: w\or: x \or: y\or: z \fi: } \def_new:Npn \int_Alph_default_conversion_rule:n #1{ \if_case:w #1 \or: A\or: B\or: C\or: D\or: E\or: F \or: G\or: H\or: I\or: J\or: K\or: L \or: M\or: N\or: O\or: P\or: Q\or: R \or: S\or: T\or: U\or: V\or: W\or: X \or: Y\or: Z \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\int_to_alph:n} % \begin{macro}{\int_to_Alph:n} % The actual functions are just instances of the generic function. The % second argument of |\int_convert_number_with_rule:nnN| should of % course match the number of |\or:|s in the conversion rule. % \begin{macrocode} \def_new:Npn \int_to_alph:n #1{ \int_convert_number_with_rule:nnN {#1}{26} \int_alph_default_conversion_rule:n } \def_new:Npn \int_to_Alph:n #1{ \int_convert_number_with_rule:nnN {#1}{26} \int_Alph_default_conversion_rule:n } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_to_symbol:n} % Turning a number into a symbol is also easy enough. % \begin{macrocode} \def_new:Npn \int_to_symbol:n #1{ \mode_if_math:TF { \int_convert_number_with_rule:nnN {#1}{9} \int_symbol_math_conversion_rule:n } { \int_convert_number_with_rule:nnN {#1}{9} \int_symbol_text_conversion_rule:n } } % \end{macrocode} % \end{macro} % \begin{macro}{\int_symbol_math_conversion_rule:n} % \begin{macro}{\int_symbol_text_conversion_rule:n} % Nothing spectacular here. % \begin{macrocode} \def_new:Npn \int_symbol_math_conversion_rule:n #1 { \if_case:w #1 \or: * \or: \dagger \or: \ddagger \or: \mathsection \or: \mathparagraph \or: \| \or: ** \or: \dagger\dagger \or: \ddagger\ddagger \fi: } \def_new:Npn \int_symbol_text_conversion_rule:n #1 { \if_case:w #1 \or: \textasteriskcentered \or: \textdagger \or: \textdaggerdbl \or: \textsection \or: \textparagraph \or: \textbardbl \or: \textasteriskcentered\textasteriskcentered \or: \textdagger\textdagger \or: \textdaggerdbl\textdaggerdbl \fi: } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\l_tmpa_int} % \begin{macro}{\l_tmpb_int} % \begin{macro}{\l_tmpc_int} % \begin{macro}{\g_tmpa_int} % \begin{macro}{\g_tmpb_int} % \begin{macro}{\l_loop_int} % We provide four local and two global scratch counters, maybe we % need more or less. % \begin{macrocode} \int_new:N \l_tmpa_int \int_new:N \l_tmpb_int \int_new:N \l_tmpc_int \int_new:N \g_tmpa_int \int_new:N \g_tmpb_int \int_new:N \l_loop_int % a variable for use in loops (whilenum etc) % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_eval:n} % \begin{macro}{\int_eval:w} % \begin{macro}{\int_eval_end:} % Evaluating a calc expression using normal operators. Many of these % are exactly the same as the ones in the \textsf{num} module so we % just use them. % \begin{macrocode} \let_new:NN \int_eval:n \num_eval:n \let_new:NN \int_eval:w \num_eval:w \let_new:NN \int_eval_end: \num_eval_end: % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\c_max_int} % The largest number allowed is $2^{31}-1$ % \begin{macrocode} \const_new:Nn \c_max_int {2147483647} % \end{macrocode} % \end{macro} % % \begin{macro}{\int_pre_eval_one_arg:Nn} % \begin{macro}{\int_pre_eval_two_args:Nnn} % These might be handy when handing down values to other % functions. All they do is evaluate the number in advance. % \begin{macrocode} \def:Npn \int_pre_eval_one_arg:Nnn #1#2{\exp_args:No#1{\int_eval:w#2}} \def:Npn \int_pre_eval_two_args:Nnn #1#2#3{ \exp_args:Noo#1{\int_use:N\int_eval:w#2}{\int_use:N\int_eval:w#3} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\int_div_truncate:nn} % \begin{macro}{\int_div_round:nn} % \begin{macro}{\int_mod:nn} % \begin{macro}{\int_div_truncate_raw:nn} % \begin{macro}{\int_div_round_raw:nn} % \begin{macro}{\int_mod_raw:nn} % As "\num_eval:w" rounds the result of a division we also % provide a version that truncates the result. % \begin{macrocode} \def_new:Npn \int_div_truncate:nn { \int_pre_eval_two_args:Nnn\int_div_truncate_raw:nn } % \end{macrocode} % Initial version didn't work correctly with e\TeX's implementation. % \begin{macrocode} %\def_new:Npn \int_div_truncate_raw:nn #1#2 { % \int_eval:n{ (2*#1 - #2) / (2* #2) } %} % \end{macrocode} % New version by Heiko: % \begin{macrocode} \def_new:Npn \int_div_truncate_raw:nn #1#2 { \int_eval:w \if_num:w \int_eval:w#1 = \c_zero 0 \else: (#1 \if_num:w \int_eval:w #1 < \c_zero \if_num:w \int_eval:w#2 < \c_zero -( #2 + \else: +( #2 - \fi: \else: \if_num:w \int_eval:w #2 < \c_zero +( #2 + \else: -( #2 - \fi: \fi: 1)/2) \fi: /(#2) \int_eval_end: } % \end{macrocode} % For the sake of completeness: % \begin{macrocode} \def_new:Npn \int_div_round:nn { \int_pre_eval_two_args:Nnn\int_div_round_raw:nn } \def_new:Npn \int_div_round_raw:nn #1#2 {\int_eval:n{#1/#2}} % \end{macrocode} % Finally there's the modulus operation. % \begin{macrocode} \def_new:Npn \int_mod:nn {\int_pre_eval_two_args:Nnn\int_mod_raw:nn} \def_new:Npn \int_mod_raw:nn #1#2 { \int_eval:n{ #1 - \int_div_truncate_raw:nn {#1}{#2} * #2 } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_compare:nNnTF} % \begin{macro}{\int_compare:nNnT} % \begin{macro}{\int_compare:nNnF} % Simple comparison tests. % \begin{macrocode} \let_new:NN \int_compare:nNnTF \num_compare:nNnTF \let_new:NN \int_compare:nNnT \num_compare:nNnT \let_new:NN \int_compare:nNnF \num_compare:nNnF % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_max_of:nn} % \begin{macro}{\int_min_of:nn} % \begin{macro}{\int_abs:n} % Simple comparison tests. % \begin{macrocode} \let_new:NN \int_max_of:nn \num_max_of:nn \let_new:NN \int_min_of:nn \num_min_of:nn \let_new:NN \int_abs:nn \num_abs:nn % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_compare_p:nNn} % A predicate function. % \begin{macrocode} \let_new:NN \int_compare_p:nNn \num_compare_p:nNn % \end{macrocode} % \end{macro} % % \begin{macro}{\int_if_odd_p:n} % \begin{macro}{\int_if_odd:nTF} % \begin{macro}{\int_if_odd:nT} % \begin{macro}{\int_if_odd:nF} % A predicate function. % \begin{macrocode} \def_new:Npn \int_if_odd_p:n #1 { \if_num_odd:w \int_eval:n{#1} \c_true \else: \c_false \fi: } \def_test_function_new:npn {int_if_odd:n}#1{\if_num_odd:w \int_eval:n{#1}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\int_whiledo:nNnT} % \begin{macro}{\int_whiledo:nNnF} % \begin{macro}{\int_dowhile:nNnT} % \begin{macro}{\int_dowhile:nNnF} % These are quite easy given the above functions. The "while" versions % test first and then execute the body. The "dowhile" does it the % other way round. The have to be defined as ``long'' since the "T" argument % might contain "\par" tokens. % \begin{macrocode} \def_long_new:Npn \int_whiledo:nNnT #1#2#3#4{ \int_compare:nNnT {#1}#2{#3}{#4 \int_whiledo:nNnT {#1}#2{#3}{#4}} } \def_long_new:Npn \int_whiledo:nNnF #1#2#3#4{ \int_compare:nNnF {#1}#2{#3}{#4 \int_whiledo:nNnF {#1}#2{#3}{#4}} } \def_long_new:Npn \int_dowhile:nNnT #1#2#3#4{ #4 \int_compare:nNnT {#1}#2{#3}{\int_dowhile:nNnT {#1}#2{#3}{#4}} } \def_long_new:Npn \int_dowhile:nNnF #1#2#3#4{ #4 \int_compare:nNnF {#1}#2{#3}{\int_dowhile:nNnF {#1}#2{#3}{#4}} } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \subsubsection{Scanning and conversion} % % % Conversion between different numbering schemes requires meticulous % work. A number can be preceeded by any number of |+| and/or |-|. We % define a generic function which will return the sign and/or the % remainder. % % \begin{macro}{\int_get_sign_and_digits:n} % \begin{macro}{\int_get_sign:n} % \begin{macro}{\int_get_digits:n} % \begin{macro}{\int_get_sign_and_digits_aux:nNNN} % \begin{macro}{\int_get_sign_and_digits_aux:oNNN} % A number may be preceeded by any number of |+|s and |-|s. Start out % by assuming we have a positive number. % \begin{macrocode} \def_new:Npn \int_get_sign_and_digits:n #1{ \int_get_sign_and_digits_aux:nNNN {#1} \c_true \c_true \c_true } \def_new:Npn \int_get_sign:n #1{ \int_get_sign_and_digits_aux:nNNN {#1} \c_true \c_true \c_false } \def_new:Npn \int_get_digits:n #1{ \int_get_sign_and_digits_aux:nNNN {#1} \c_true \c_false \c_true } % \end{macrocode} % Now check the first character in the string. Only a |-| can change % if a number is positive or negative, hence we reverse the boolean % governing this. Then gobble the |-| and start over. % \begin{macrocode} \def_new:Npn \int_get_sign_and_digits_aux:nNNN #1#2#3#4{ \tlist_if_head_eq_charcode:fNTF {#1} - { \bool_if:NTF #2 { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} \c_false #3#4 } { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} \c_true #3#4 } } % \end{macrocode} % The other cases are much simpler since we either just have to gobble % the |+| or exit immediately and insert the correct sign. % \begin{macrocode} { \tlist_if_head_eq_charcode:fNTF {#1} + { \int_get_sign_and_digits_aux:oNNN {\use_none:n #1} #2#3#4} { % \end{macrocode} % The boolean |#3| is for printing the sign while |#4| is for printing % the digits. % \begin{macrocode} \bool_double_if:NNnnnn #3#4 { \bool_if:NF #2 - #1 } { \bool_if:NF #2 - } { #1 } { } } } } \def_new:Npn \int_get_sign_and_digits_aux:oNNN{ \exp_args:No\int_get_sign_and_digits_aux:nNNN } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\int_convert_from_base_ten:nn} % \begin{macro}{\int_convert_from_base_ten_aux:nnn} % \begin{macro}{\int_convert_from_base_ten_aux:non} % \begin{macro}{\int_convert_from_base_ten_aux:fon} % |#1| is the base 10 number to be converted to base |#2|. We split % off the sign first, print if if there and then convert only the % number. Since this is supposedly a base~10 number we can let \TeX\ % do the reading of |+| and |-|. % \begin{macrocode} \def:Npn \int_convert_from_base_ten:nn#1#2{ \num_compare:nNnTF {#1}<\c_zero { - \int_convert_from_base_ten_aux:non {} { \int_use:N \int_eval:n {-#1} } } { \int_convert_from_base_ten_aux:non {} { \int_use:N \int_eval:n {#1} } } {#2} } % \end{macrocode} % The algorithm runs like this: % \begin{enumerate} % \item If the number \meta{num} is greater than \meta{base}, % calculate modulus of \meta{num} and \meta{base} and carry that % over for next round. The remainder is calculated as a truncated % division of \meta{num} and \meta{base}. Start over with these new % values. % \item If \meta{num} is less than or equal to \meta{base} convert it % to the correct symbol, print the previously calculated digits and % exit. % \end{enumerate} % |#1| is the carried over result, |#2| the remainder and |#3| the % base number. % \begin{macrocode} \def_new:Npn \int_convert_from_base_ten_aux:nnn#1#2#3{ \num_compare:nNnTF {#2}<{#3} { \int_convert_number_to_letter:n{#2} #1 } { \int_convert_from_base_ten_aux:fon { \int_convert_number_to_letter:n {\int_use:N\int_mod_raw:nn {#2}{#3}} #1 } {\int_use:N \int_div_truncate_raw:nn{#2}{#3}} {#3} } } \def:Npn \int_convert_from_base_ten_aux:non{ \exp_args:Nno\int_convert_from_base_ten_aux:nnn } \def:Npn \int_convert_from_base_ten_aux:fon{ \exp_args:Nfo\int_convert_from_base_ten_aux:nnn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \begin{macro}{\int_convert_number_to_letter:n} % Turning a number for a different base into a letter or digit. % \begin{macrocode} \def:Npn \int_convert_number_to_letter:n #1{ \if_case:w \int_eval:w #1-10\scan_stop: \exp_after:NN A \or: \exp_after:NN B \or: \exp_after:NN C \or: \exp_after:NN D \or: \exp_after:NN E \or: \exp_after:NN F \or: \exp_after:NN G \or: \exp_after:NN H \or: \exp_after:NN I \or: \exp_after:NN J \or: \exp_after:NN K \or: \exp_after:NN L \or: \exp_after:NN M \or: \exp_after:NN N \or: \exp_after:NN O \or: \exp_after:NN P \or: \exp_after:NN Q \or: \exp_after:NN R \or: \exp_after:NN S \or: \exp_after:NN T \or: \exp_after:NN U \or: \exp_after:NN V \or: \exp_after:NN W \or: \exp_after:NN X \or: \exp_after:NN Y \or: \exp_after:NN Z \else: \use_arg_i_after_fi:nw{ #1 }\fi: } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_convert_to_base_ten:nn} % |#1| is the number, |#2| is its base. First we get the sign, then % use only the digits/letters from it and pass that onto a new % function. % \begin{macrocode} \def:Npn \int_convert_to_base_ten:nn #1#2 { \int_use:N\int_eval:n{ \int_get_sign:n{#1} \exp_args:Nf\int_convert_to_base_ten_aux:nn {\int_get_digits:n{#1}}{#2} } } % \end{macrocode} % This is an intermediate function to get things started. % \begin{macrocode} \def_new:Npn \int_convert_to_base_ten_aux:nn #1#2{ \int_convert_to_base_ten_auxi:nnN {0}{#2} #1 \q_nil } % \end{macrocode} % Here we check each letter/digit and calculate the next number. |#1| % is the previously calculated result (to be multiplied by the base), % |#2| is the base and |#3| is the next letter/digit to be added. % \begin{macrocode} \def_new:Npn \int_convert_to_base_ten_auxi:nnN#1#2#3{ \quark_if_nil:NTF #3 {#1} {\exp_args:No\int_convert_to_base_ten_auxi:nnN {\int_use:N \int_eval:n{ #1*#2+\int_convert_letter_to_number:N #3} } {#2} } } % \end{macrocode} % This is for turning a letter or digit into a number. This function % also takes care of handling lowercase and uppercase letters. Hence % |a| is turned into |11| and so is |A|. % \begin{macrocode} \def:Npn \int_convert_letter_to_number:N #1{ \int_compare:nNnTF{`#1}<{58}{#1} { \int_eval:n{ `#1 - \if:w\int_compare_p:nNn{`#1}<{91} 55 \else: 87 \fi: } } } % \end{macrocode} % \end{macro} % % % % % % % % Show token usage: % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode} % % % \endinput % % $Log$ % Revision 1.26 2006/06/03 17:17:08 morten % Functions for converting between number bases % % Revision 1.25 2006/03/20 18:26:35 braams % Updated the copyright notice (2006) and demoted all implementation % sections to subsections and so on to clean up the toc for source3.tex % % Revision 1.24 2006/01/17 22:47:43 morten % Changed \int_while:nNnT to \int_whiledo:nNnT to avoid confusion with % the dowhile versions. % % Revision 1.23 2005/12/27 10:02:37 morten % Minor changes plus changed RCS information retrieval % % Revision 1.22 2005/12/21 20:43:32 morten % Fixed silly bugs! % % Revision 1.21 2005/12/06 17:31:23 morten % fixed \int_convert_number_with_rule:nnN % % Revision 1.20 2005/12/06 14:49:36 morten % Fixed primitive names plus a few minor touch-ups % % Revision 1.19 2005/04/25 15:02:47 morten % Added ifodd functions % % Revision 1.18 2005/04/09 21:07:39 morten % Added (extensible) implementations of \int_to_roman:n etc. % % Revision 1.17 2005/04/06 22:35:43 braams % Now we have register allocation fitted % % Revision 1.16 2005/03/25 23:48:47 braams % Added a missing \end{macro} % % Revision 1.15 2005/03/22 23:22:09 morten % Moved definitions of constants to l3num % % Revision 1.14 2005/03/16 22:36:30 braams % Added the tweaks necessary to be able to load with initex % % Revision 1.13 2005/03/11 21:38:31 braams % Fixed the use of RCS information; added \StopEventually %