% \iffalse %% File: l3calc.dtx Copyright (C) 2006 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. %% %% ----------------------------------------------------------------------- %\RequirePackage{l3names} %<*dtx> %\fi \def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% \def\fileversion{#2}% \def\filedate{#3/#4/#5}% \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% } %\iffalse % %\fi \GetIdInfo$Id: l3calc.dtx 573 2006-08-21 20:59:37Z morten $ {L3 Experimental calc module} % \iffalse %<*driver> \documentclass{l3doc} \begin{document} \DocInput{l3calc.dtx} \end{document} % % \fi % % \title{The \textsf{l3calc} package\thanks{This file has version % number \fileversion, last % revised \filedate.}\\ % Infix notation arithmetic in \LaTeX3} % \author{\Team} % \date{\filedate} % \maketitle % % \section{Infix notation arithmetic} % % This is pretty much a straight adaption of the \textsf{calc} package % and as such has same syntax for the \meta{calc expression}. However, % there are some noticeable differences. % \begin{itemize} % \item The calc expression is expanded fully, which means there are % no problems with unfinished conditionals. However, the contents of % |\widthof| etc.\ is not expanded at all. % \item Muskip registers are supported although they can only be used % in |\ratio| if already evaluating a muskip expression. For the % other three register types, you can use points. % \item All results are rounded, not truncated. More precisely, the % primitive \TeX\ operations |\divide| and |\multiply| are not used. % \end{itemize} % % \begin{function}{ % \calc_int_set:Nn | % \calc_int_gset:Nn | % \calc_int_add:Nn | % \calc_int_gadd:Nn | % \calc_int_sub:Nn | % \calc_int_gsub:Nn | % } % \begin{syntax} % "\calc_int_set:Nn" "{""}" % \end{syntax} % Evaluates and either adds or subtracts it from % or sets to it. These operations can also be global. % \end{function} % % % \begin{function}{ % \calc_dim_set:Nn | % \calc_dim_gset:Nn | % \calc_dim_add:Nn | % \calc_dim_gadd:Nn | % \calc_dim_sub:Nn | % \calc_dim_gsub:Nn | % } % \begin{syntax} % "\calc_dim_set:Nn" "{""}" % \end{syntax} % Evaluates and either adds or subtracts it from % or sets to it. These operations can also be global. % \end{function} % % % \begin{function}{ % \calc_skip_set:Nn | % \calc_skip_gset:Nn | % \calc_skip_add:Nn | % \calc_skip_gadd:Nn | % \calc_skip_sub:Nn | % \calc_skip_gsub:Nn | % } % \begin{syntax} % "\calc_skip_set:Nn" "{""}" % \end{syntax} % Evaluates and either adds or subtracts it from % or sets to it. These operations can also be global. % \end{function} % % % \begin{function}{ % \calc_muskip_set:Nn | % \calc_muskip_gset:Nn | % \calc_muskip_add:Nn | % \calc_muskip_gadd:Nn | % \calc_muskip_sub:Nn | % \calc_muskip_gsub:Nn | % } % \begin{syntax} % "\calc_muskip_set:Nn" "{""}" % \end{syntax} % Evaluates and either adds or subtracts it from % or sets to it. These operations can also be % global. % \end{function} % % % \begin{function}{ % \calc_calculate_box_size:nnn | % } % \begin{syntax} % "\calc_calculate_box_size:nnn" "{""}" \\ % "{" ... "}" "{""}" % \end{syntax} % Sets in a temporary box "\l_tmpa_box". Then % is put in front of a loop that inserts "+"\meta{item$\sb{i}$} in % front of "\l_tmpa_box" and this is evaluated. For instance, if we % wanted to determine the total height of the text "xyz" and store % it in "\l_tmpa_dim", we would call it as. % \begin{verbatim} % \calc_calculate_box_size:nnn % {\dim_set:Nn\l_tmpa_dim}{\box_ht:N\box_dp:N}{xyz} % \end{verbatim} % Similarly, if we wanted the difference between height and depth, % we could call it as % \begin{verbatim} % \calc_calculate_box_size:nnn % {\dim_set:Nn\l_tmpa_dim}{\box_ht:N{-\box_dp:N}}{xyz} % \end{verbatim} % \end{function} % % \StopEventually{} % % \subsection{The Implementation} % % Since this is basically a re-worked version of the \textsf{calc} % package, I haven't bothered with too many comments except for in the % places where this package differs. This may (and should) change at % some point. % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<*package> \RequirePackage{l3int} \RequirePackage{l3skip} \RequirePackage{l3box} % %<*initex|package> % \end{macrocode} % % % \begin{macro}{\l_calc_expression_tlp} % \begin{macro}{\g_calc_A_register} % \begin{macro}{\l_calc_B_register} % \begin{macro}{\l_calc_current_type_int} % Here we define some registers and pointers we will need. % \begin{macrocode} \tlp_new:Nn\l_calc_expression_tlp{} \def_new:Npn \g_calc_A_register{} \def_new:Npn \l_calc_B_register{} \int_new:N \l_calc_current_type_int % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\g_calc_A_int} % \begin{macro}{\l_calc_B_int} % \begin{macro}{\l_calc_C_int} % \begin{macro}{\g_calc_A_dim} % \begin{macro}{\l_calc_B_dim} % \begin{macro}{\l_calc_C_dim} % \begin{macro}{\g_calc_A_skip} % \begin{macro}{\l_calc_B_skip} % \begin{macro}{\l_calc_C_skip} % \begin{macro}{\g_calc_A_muskip} % \begin{macro}{\l_calc_B_muskip} % \begin{macro}{\l_calc_C_muskip} % For each type of register we will need three registers to do our % manipulations. % \begin{macrocode} \int_new:N \g_calc_A_int \int_new:N \l_calc_B_int \int_new:N \l_calc_C_int \dim_new:N \g_calc_A_dim \dim_new:N \l_calc_B_dim \dim_new:N \l_calc_C_dim \skip_new:N \g_calc_A_skip \skip_new:N \l_calc_B_skip \skip_new:N \l_calc_C_skip \muskip_new:N \g_calc_A_muskip \muskip_new:N \l_calc_B_muskip \muskip_new:N \l_calc_C_muskip % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % % \begin{macro}{\calc_assign_generic:NNNNNn} % The generic function. |#1| is a number denoting which type we are % doing. (0=int, 1=dim, 2=skip, 3=muskip), |#2| = temp register A, % |#3| = temp register B, |#4| is a function acting on |#5| which is % the register to be set. |#6| is the calc expression. This version % relies on |\real| and |\ratio| having our definitions. % \begin{macrocode} \def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{ \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3 \int_set:Nn \l_calc_current_type_int {#1} \tlp_set:Nx\l_calc_expression_tlp{#6} \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp! \pref_global:D\g_calc_A_register\l_calc_B_register \group_end: #4#5\l_calc_B_register } % \end{macrocode} % One could lift these restrictions by defining |\calc_generic:NNNNNn| % like this: % \begin{verbatim} % \def_long_new:Npn \calc_assign_generic:NNNNNn#1#2#3#4#5#6{ % \let:NN\g_calc_A_register#2\let:NN\l_calc_B_register#3 % \int_set:Nn \l_calc_current_type_int {#1} % \group_begin: % \let:NN \real\calc_real:n % \let:NN \ratio\calc_ratio:nn % \tlp_set:Nx\l_calc_expression_tlp{#6} % \exp_after:NN % \group_end: % \exp_after:NN\calc_open:w\exp_after:NN(\l_calc_expression_tlp! % \pref_global:D\g_calc_A_register\l_calc_B_register % \group_end: % #4#5\l_calc_B_register % } % \end{verbatim} % \end{macro} % % % % \begin{macro}{\calc_int_set:Nn} % \begin{macro}{\calc_int_gset:Nn} % \begin{macro}{\calc_int_add:Nn} % \begin{macro}{\calc_int_gadd:Nn} % \begin{macro}{\calc_int_sub:Nn} % \begin{macro}{\calc_int_gsub:Nn} % Here are the individual versions for the different register % types. First integer registers. % \begin{macrocode} \def_new:Npn\calc_int_set:Nn{ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_set:Nn } \def_new:Npn\calc_int_gset:Nn{ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gset:Nn } \def_new:Npn\calc_int_add:Nn{ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_add:Nn } \def_new:Npn\calc_int_gadd:Nn{ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gadd:Nn } \def_new:Npn\calc_int_sub:Nn{ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_sub:Nn } \def_new:Npn\calc_int_gsub:Nn{ \calc_assign_generic:NNNNNn\c_zero\g_calc_A_int\l_calc_B_int\int_gsub:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_dim_set:Nn} % \begin{macro}{\calc_dim_gset:Nn} % \begin{macro}{\calc_dim_add:Nn} % \begin{macro}{\calc_dim_gadd:Nn} % \begin{macro}{\calc_dim_sub:Nn} % \begin{macro}{\calc_dim_gsub:Nn} % Dimens. % \begin{macrocode} \def_new:Npn\calc_dim_set:Nn{ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_set:Nn } \def_new:Npn\calc_dim_gset:Nn{ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gset:Nn } \def_new:Npn\calc_dim_add:Nn{ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_add:Nn } \def_new:Npn\calc_dim_gadd:Nn{ \calc_assign_generic:NNNNNn\c_one\g_calc_A_dim\l_calc_B_dim\dim_gadd:Nn } \def_new:Npn\calc_dim_sub:Nn{ \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_sub:Nn } \def_new:Npn\calc_dim_gsub:Nn{ \calc_assign_generic:NNNNNn\c_one\g_calc_A_int\l_calc_B_int\dim_gsub:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_skip_set:Nn} % \begin{macro}{\calc_skip_gset:Nn} % \begin{macro}{\calc_skip_add:Nn} % \begin{macro}{\calc_skip_gadd:Nn} % \begin{macro}{\calc_skip_sub:Nn} % \begin{macro}{\calc_skip_gsub:Nn} % Skips. % \begin{macrocode} \def_new:Npn\calc_skip_set:Nn{ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_set:Nn } \def_new:Npn\calc_skip_gset:Nn{ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gset:Nn } \def_new:Npn\calc_skip_add:Nn{ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_add:Nn } \def_new:Npn\calc_skip_gadd:Nn{ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gadd:Nn } \def_new:Npn\calc_skip_sub:Nn{ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_sub:Nn } \def_new:Npn\calc_skip_gsub:Nn{ \calc_assign_generic:NNNNNn\c_two\g_calc_A_dim\l_calc_B_dim\skip_gsub:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_muskip_set:Nn} % \begin{macro}{\calc_muskip_gset:Nn} % \begin{macro}{\calc_muskip_add:Nn} % \begin{macro}{\calc_muskip_gadd:Nn} % \begin{macro}{\calc_muskip_sub:Nn} % \begin{macro}{\calc_muskip_gsub:Nn} % Muskips. % \begin{macrocode} \def_new:Npn\calc_muskip_set:Nn{ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_set:Nn } \def_new:Npn\calc_muskip_gset:Nn{ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gset:Nn } \def_new:Npn\calc_muskip_add:Nn{ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn } \def_new:Npn\calc_muskip_gadd:Nn{ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn } \def_new:Npn\calc_muskip_sub:Nn{ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_add:Nn } \def_new:Npn\calc_muskip_gsub:Nn{ \calc_assign_generic:NNNNNn\c_three\g_calc_A_dim\l_calc_B_dim\muskip_gadd:Nn } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\calc_pre_scan:N} % In case we found one of the special operations, this should just % be executed. % \begin{macrocode} \def_new:Npn \calc_pre_scan:N #1{ \if_meaning:NN(#1 \exp_after:NN\calc_open:w \else: \if_meaning:NN \calc_textsize:Nn #1 \else: \if_meaning:NN \calc_maxmin_operation:Nnn #1 \else: % \end{macrocode} % |\calc_numeric:| uses a primitive assignment so doesn't care about % these dangling |\fi:|s. % \begin{macrocode} \calc_numeric: \fi: \fi: \fi: #1} % \end{macrocode} % \end{macro} % % \begin{macro}{\calc_open:w} % \begin{macrocode} \def_new:Npn \calc_open:w({ \group_begin:\group_execute_after:N\calc_init_B: \group_begin:\group_execute_after:N\calc_init_B: \calc_pre_scan:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\calc_init_B:} % \begin{macro}{\calc_numeric:} % \begin{macro}{\calc_close:} % \begin{macrocode} \def_new:Npn\calc_init_B:{\l_calc_B_register\g_calc_A_register} \def_new:Npn\calc_numeric:{ \tex_afterassignment:D\calc_post_scan:N \pref_global:D\g_calc_A_register } \def_new:Npn\calc_close:{ \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register \group_end:\pref_global:D\g_calc_A_register\l_calc_B_register \calc_post_scan:N} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_post_scan:N} % Look at what token we have and decide where to go. % \begin{macrocode} \def_new:Npn\calc_post_scan:N#1{ \if_meaning:NN#1!\let:NN\calc_next:w\group_end: \else: \if_meaning:NN#1+\let:NN\calc_next:w\calc_add: \else: \if_meaning:NN#1-\let:NN\calc_next:w\calc_subtract: \else: \if_meaning:NN#1*\let:NN\calc_next:w\calc_multiply:N \else: \if_meaning:NN#1/\let:NN\calc_next:w\calc_divide:N \else: \if_meaning:NN#1)\let:NN\calc_next:w\calc_close: \else: % \end{macrocode} % If we get here, there is an error but let's also disable % |\calc_next:w| since it is otherwise undefined. No need to give % extra errors just for that. % \begin{macrocode} \let:NN \calc_next:w \scan_stop: \calc_error:N#1 \fi: \fi: \fi: \fi: \fi: \fi: \calc_next:w} % \end{macrocode} % \end{macro} % % \begin{macro}{\calc_multiply:N} % \begin{macro}{\calc_divide:N} % The switches for multiplication and division. % \begin{macrocode} \def_new:Npn \calc_multiply:N #1{ \if_meaning:NN \calc_maxmin_operation:Nnn #1 \let:NN \calc_next:w \calc_maxmin_multiply: \else: \if_meaning:NN \calc_ratio_multiply:nn #1 \let:NN \calc_next:w \calc_ratio_multiply:nn \else: \if_meaning:NN \calc_real_evaluate:nn #1 \let:NN \calc_next:w \calc_real_multiply:n \else: \def:Npn \calc_next:w{\calc_multiply: #1} \fi: \fi: \fi: \calc_next:w } \def_new:Npn \calc_divide:N #1{ \if_meaning:NN \calc_maxmin_operation:Nnn #1 \let:NN \calc_next:w \calc_maxmin_divide: \else: \if_meaning:NN \calc_ratio_multiply:nn #1 \let:NN \calc_next:w \calc_ratio_divide:nn \else: \if_meaning:NN \calc_real_evaluate:nn #1 \let:NN \calc_next:w \calc_real_divide:n \else: \def:Npn \calc_next:w{\calc_divide: #1} \fi: \fi: \fi: \calc_next:w } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\calc_generic_add:N} % \begin{macro}{\calc_add:} % \begin{macro}{\calc_subtract:} % \begin{macro}{\calc_add_A_to_B:} % \begin{macro}{\calc_subtract_A_from_B:} % Here is how we add and subtract. % \begin{macrocode} \def_new:Npn\calc_generic_add_or_subtract:N#1{ \group_end: \pref_global:D\g_calc_A_register\l_calc_B_register\group_end: \group_begin:\group_execute_after:N#1\group_begin: \group_execute_after:N\calc_init_B: \calc_pre_scan:N} \def_new:Npn\calc_add:{\calc_generic_add_or_subtract:N\calc_add_A_to_B:} \def_new:Npn\calc_subtract:{ \calc_generic_add_or_subtract:N\calc_subtract_A_from_B:} % \end{macrocode} % Don't use |\tex_advance:D| since it allows overflows. % \begin{macrocode} \def_new:Npn\calc_add_A_to_B:{ \l_calc_B_register \if_case:w\l_calc_current_type_int \etex_numexpr:D\or: \etex_dimexpr:D\or: \etex_glueexpr:D\or: \etex_muexpr:D\fi: \l_calc_B_register + \g_calc_A_register\scan_stop: } \def_new:Npn\calc_subtract_A_from_B:{ \l_calc_B_register \if_case:w\l_calc_current_type_int \etex_numexpr:D\or: \etex_dimexpr:D\or: \etex_glueexpr:D\or: \etex_muexpr:D\fi: \l_calc_B_register - \g_calc_A_register\scan_stop: } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_generic_multiply_or_divide:N} % \begin{macro}{\calc_multiply_B_by_A:} % \begin{macro}{\calc_divide_B_by_A:} % \begin{macro}{\calc_multiply:} % \begin{macro}{\calc_divide:} % And here is how we multiply and divide. Note that we do not use the % primitive \TeX{} operations but the expandable operations provided % by \eTeX. This means that all results are rounded not truncated! % \begin{macrocode} \def_new:Npn\calc_generic_multiply_or_divide:N#1{ \group_end: \group_begin: \let:NN\g_calc_A_register\g_calc_A_int \let:NN\l_calc_B_register\l_calc_B_int \group_execute_after:N#1\calc_pre_scan:N } \def_new:Npn\calc_multiply_B_by_A:{ \l_calc_B_register \if_case:w\l_calc_current_type_int \etex_numexpr:D\or: \etex_dimexpr:D\or: \etex_glueexpr:D\or: \etex_muexpr:D\fi: \l_calc_B_register*\g_calc_A_int\scan_stop: } \def_new:Npn\calc_divide_B_by_A:{ \l_calc_B_register \if_case:w\l_calc_current_type_int \etex_numexpr:D\or: \etex_dimexpr:D\or: \etex_glueexpr:D\or: \etex_muexpr:D\fi: \l_calc_B_register/\g_calc_A_int\scan_stop: } \def_new:Npn\calc_multiply:{ \calc_generic_multiply_or_divide:N\calc_multiply_B_by_A:} \def_new:Npn\calc_divide:{ \calc_generic_multiply_or_divide:N\calc_divide_B_by_A:} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_calculate_box_size:nnn} % \begin{macro}{\calc_calculate_box_size_aux:n} % Put something in a box and measure it. |#1| is a list of % |\box_ht:N| etc., |#2| should be |\dim_set:Nn|\meta{dim register} % or |\dim_gset:Nn|\meta{dim register} and |#3| is the contents. % \begin{macrocode} \def_long_new:Npn \calc_calculate_box_size:nnn #1#2#3{ \hbox_set:Nn \l_tmpa_box {{#3}} #2{\c_zero_dim \tlist_map_function:nN{#1}\calc_calculate_box_size_aux:n} } % \end{macrocode} % Helper for calculating the final dimension. % \begin{macrocode} \def:Npn \calc_calculate_box_size_aux:n#1{ + #1\l_tmpa_box} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\calc_textsize:Nn} % Now we can define |\calc_textsize:Nn|. % \begin{macrocode} \def_protected_long:Npn \calc_textsize:Nn#1#2{ \group_begin: \let:NN\widthof\box_wd:N \let:NN\heightof\box_ht:N \let:NN\depthof\box_dp:N \def:Npn\totalheightof{\box_ht:N\box_dp:N} \exp_args:No\calc_calculate_box_size:nnn{#1} {\dim_gset:Nn\g_calc_A_register} % \end{macrocode} % Restore the four user commands here since there might be a recursive % call. % \begin{macrocode} { \let:NN \depthof\calc_depthof:n \let:NN \widthof\calc_widthof:n \let:NN \heightof\calc_heightof:n \let:NN \totalheightof\calc_totalheightof:n #2 } \group_end: \calc_post_scan:N } % \end{macrocode} % \end{macro} % % \begin{macro}{\calc_ratio_multiply:nn} % \begin{macro}{\calc_ratio_divide:nn} % Evaluate a ratio. If we were already evaluation a \meta{muskip} % register, the ratio is probably also done with this type and we'll % have to convert them to regular points. % \begin{macrocode} \def_protected_long:Npn\calc_ratio_multiply:nn#1#2{ \group_end:\group_begin: \if_num:w\l_calc_current_type_int < \c_three \calc_dim_set:Nn\l_calc_B_int{#1} \calc_dim_set:Nn\l_calc_C_int{#2} \else: \calc_dim_muskip:Nn{\l_calc_B_int\etex_mutoglue:D}{#1} \calc_dim_muskip:Nn{\l_calc_C_int\etex_mutoglue:D}{#2} \fi: % \end{macrocode} % Then store the ratio as a fraction, which we just pass on. % \begin{macrocode} \gdef:Npx\calc_calculated_ratio:{ \int_use:N\l_calc_B_int/\int_use:N\l_calc_C_int } \group_end: % \end{macrocode} % Here we set the new value of |\l_calc_B_register| and remember to % evaluate it as the correct type. Note that the intermediate % calculation is a scaled operation (meaning the intermediate value is % 64-bit) so we don't get into trouble when first multiplying by a % large number and then dividing. % \begin{macrocode} \l_calc_B_register \if_case:w\l_calc_current_type_int \etex_numexpr:D\or: \etex_dimexpr:D\or: \etex_glueexpr:D\or: \etex_muexpr:D\fi: \l_calc_B_register*\calc_calculated_ratio:\scan_stop: \group_begin: \calc_post_scan:N} % \end{macrocode} % Division is just flipping the arguments around. % \begin{macrocode} \def_long_new:Npn \calc_ratio_divide:nn#1#2{\calc_ratio_multiply:nn{#2}{#1}} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\calc_real_evaluate:nn} % \begin{macro}{\calc_real_multiply:n} % \begin{macro}{\calc_real_divide:n} % Although we could define the |\real| function as a subcase of % |\ratio|, this is horribly inefficient since we just want to convert % the decimal to a fraction. % \begin{macrocode} \def_protected_new:Npn\calc_real_evaluate:nn #1#2{ \group_end: \l_calc_B_register \if_case:w\l_calc_current_type_int \etex_numexpr:D\or: \etex_dimexpr:D\or: \etex_glueexpr:D\or: \etex_muexpr:D\fi: \l_calc_B_register * \tex_number:D \dim_eval:n{#1pt}/ \tex_number:D\dim_eval:n{#2pt} \scan_stop: \group_begin: \calc_post_scan:N} \def_new:Npn \calc_real_multiply:n #1{\calc_real_evaluate:nn{#1}{1}} \def_new:Npn \calc_real_divide:n {\calc_real_evaluate:nn{1}} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_maxmin_operation:Nnn} % \begin{macro}{\calc_maxmin_generic:Nnn} % \begin{macro}{\calc_maxmin_div_or_mul:NNnn} % \begin{macro}{\calc_maxmin_multiply:} % \begin{macro}{\calc_maxmin_multiply:} % The max and min functions. % \begin{macrocode} \def_protected_long:Npn\calc_maxmin_operation:Nnn#1#2#3{ \group_begin: \calc_maxmin_generic:Nnn#1{#2}{#3} \group_end: \calc_post_scan:N } % \end{macrocode} % |#1| is either |>| or |<| and was expanded into this initially. % \begin{macrocode} \def_protected_long_new:Npn \calc_maxmin_generic:Nnn#1#2#3{ \group_begin: \if_case:w\l_calc_current_type_int \calc_int_set:Nn\l_calc_C_int{#2}% \calc_int_set:Nn\l_calc_B_int{#3}% \pref_global:D\g_calc_A_register \if_num:w\l_calc_C_int#1\l_calc_B_int \l_calc_C_int\else:\l_calc_B_int\fi: \or: \calc_dim_set:Nn\l_calc_C_dim{#2}% \calc_dim_set:Nn\l_calc_B_dim{#3}% \pref_global:D\g_calc_A_register \if_dim:w\l_calc_C_dim#1\l_calc_B_dim \l_calc_C_dim\else:\l_calc_B_dim\fi: \or: \calc_skip_set:Nn\l_calc_C_skip{#2}% \calc_skip_set:Nn\l_calc_B_skip{#3}% \pref_global:D\g_calc_A_register \if_dim:w\l_calc_C_skip#1\l_calc_B_skip \l_calc_C_skip\else:\l_calc_B_skip\fi: \else: \calc_muskip_set:Nn\l_calc_C_muskip{#2}% \calc_muskip_set:Nn\l_calc_B_muskip{#3}% \pref_global:D\g_calc_A_register \if_dim:w\l_calc_C_muskip#1\l_calc_B_muskip \l_calc_C_muskip\else:\l_calc_B_muskip\fi: \fi: \group_end: } \def_long_new:Npn\calc_maxmin_div_or_mul:NNnn#1#2#3#4{ \group_end: \group_begin: \int_zero:N\l_calc_current_type_int \group_execute_after:N#1 \calc_maxmin_generic:Nnn#2{#3}{#4} \group_end: \group_begin: \calc_post_scan:N } \def_new:Npn\calc_maxmin_multiply:{ \calc_maxmin_div_or_mul:NNnn\calc_multiply_B_by_A:} \def_new:Npn\calc_maxmin_divide: { \calc_maxmin_div_or_mul:NNnn\calc_divide_B_by_A:} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_error:N} % The error message. % \begin{macrocode} \def_new:Npn\calc_error:N#1{ \PackageError{calc} {`\token_to_string:N#1'~ invalid~ at~ this~ point} {I~ expected~ to~ see~ one~ of:~ +~ -~ *~ /~ )} } % \end{macrocode} % \end{macro} % % \subsection{Higher level commands} % % The various operations allowed. % % \begin{macro}{\calc_maxof:nn} % \begin{macro}{\calc_minof:nn} % \begin{macro}{\maxof} % \begin{macro}{\minof} % Max and min operations % \begin{macrocode} \def_long_new:Npn \calc_maxof:nn#1#2{ \calc_maxmin_operation:Nnn > \exp_not:n{{#1}{#2}} } \def_long_new:Npn \calc_minof:nn#1#2{ \calc_maxmin_operation:Nnn < \exp_not:n{{#1}{#2}} } \let_new:NN \maxof \calc_maxof:nn \let_new:NN \minof \calc_minof:nn % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_widthof:n} % \begin{macro}{\calc_heightof:n} % \begin{macro}{\calc_depthof:n} % \begin{macro}{\calc_totalheightof:n} % \begin{macro}{\widthof} % \begin{macro}{\heightof} % \begin{macro}{\depthof} % \begin{macro}{\totalheightof} % Text dimension commands. % \begin{macrocode} \def_long_new:Npn \calc_widthof:n#1{ \calc_textsize:Nn \exp_not:N\widthof\exp_not:n{{#1}} } \def_long_new:Npn \calc_heightof:n#1{ \calc_textsize:Nn \exp_not:N\heightof\exp_not:n{{#1}} } \def_long_new:Npn \calc_depthof:n#1{ \calc_textsize:Nn \exp_not:N\depthof\exp_not:n{{#1}} } \def_long_new:Npn \calc_totalheightof:n#1{ \calc_textsize:Nn \exp_not:N\totalheightof\exp_not:n{{#1}} } \let:NN \depthof\calc_depthof:n \let:NN \widthof\calc_widthof:n \let:NN \heightof\calc_heightof:n \let:NN \totalheightof\calc_totalheightof:n % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\calc_ratio:nn} % \begin{macro}{\calc_real:n} % \begin{macro}{\ratio} % \begin{macro}{\real} % Ratio and real. % \begin{macrocode} \def_long_new:Npn \calc_ratio:nn#1#2{ \calc_ratio_multiply:nn\exp_not:n{{#1}{#2}}} \let_new:NN \calc_real:n \calc_real_evaluate:nn % \end{macrocode} % We can implement real and ratio without actually using these % names. We'll see. % \begin{macrocode} \let_new:NN \ratio\calc_ratio:nn \let_new:NN \real\calc_real:n % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macrocode} % %<*showmemory> \showMemUsage % % \end{macrocode} % % \endinput % % $Log$ % Revision 1.2 2006/01/27 23:11:47 morten % Fixed bug in \calc_pre_scan:N and avoid using \advance in order to % catch overflows. % % Revision 1.1 2006/01/27 07:51:13 morten % Initial version of a calc module %