texlive[43159] Master: longdivision (6feb17)

commits+karl at tug.org commits+karl at tug.org
Tue Feb 7 00:37:59 CET 2017


Revision: 43159
          http://tug.org/svn/texlive?view=revision&revision=43159
Author:   karl
Date:     2017-02-07 00:37:59 +0100 (Tue, 07 Feb 2017)
Log Message:
-----------
longdivision (6feb17)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/longdivision/
    trunk/Master/texmf-dist/doc/latex/longdivision/README
    trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.pdf
    trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.tex
    trunk/Master/texmf-dist/tex/latex/longdivision/
    trunk/Master/texmf-dist/tex/latex/longdivision/longdivision.sty
    trunk/Master/tlpkg/tlpsrc/longdivision.tlpsrc

Added: trunk/Master/texmf-dist/doc/latex/longdivision/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/longdivision/README	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/longdivision/README	2017-02-06 23:37:59 UTC (rev 43159)
@@ -0,0 +1,22 @@
+Package: longdivision.sty version 1.0
+Author: Hood Chatham
+Email: hood at mit.edu
+Date: 2017-02-05
+Files:
+    longdivision.sty
+    longdivision_example.tex
+    longdivision_example.pdf
+    README
+
+License: All files have the Latex Project Public License.
+
+
+Does long division. The dividend must be a positive decimal number and the divisor must be a positive integer. Correctly handles repeating decimals, putting a bar over the repeated part of the decimal. Handles dividends up to 20 digits long gracefully (though the typeset result will take up about a page) and dividends between 20 and 60 digits long slightly less gracefully.
+
+Defines macros \longdivision and \intlongdivision. Each takes two arguments, a dividend and divisor. \longdivision keeps dividing until the remainder is zero, or it encounters a repeated remainder. \longdivision stops when the dividend stops (though the dividend doesn't have to be an integer).
+
+\longdivision also has an optional argument "max_extra_digits". If max_extra_digits is 0, the behavior is like \intlongdivision, whereas if max_extra_digits is greater than 60, the behavior is the same as \longdivision without the optional argument. In general, \longdivision won't add more than "max_extra_digits"  It might be prudent to use this optional argument if you are computing, say, 1/97 which has a 96 digit period (\longdivision will stop anyways to avoid overfull boxes, but the result might not be ideal).
+
+\intlongdivision behaves similarly to the \longdiv command defined in longdiv.tex, though I think \intlongdivision looks better, and it can handle much larger dividends and divisors (the dividend is only constrained by the size of the page, and the divisor can be up to 8 digits long).
+
+Please email me if you discover any bugs or have any feature requests. 
\ No newline at end of file

Added: trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.pdf	2017-02-06 23:37:17 UTC (rev 43158)
+++ trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.pdf	2017-02-06 23:37:59 UTC (rev 43159)

Property changes on: trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.tex	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/longdivision/longdivision_example.tex	2017-02-06 23:37:59 UTC (rev 43159)
@@ -0,0 +1,40 @@
+\documentclass{article}
+\usepackage{longdivision}
+
+\begin{document}
+
+\longdivision{72344}{7}
+%
+\qquad\qquad\qquad
+%
+\longdivision[2]{72344}{7}
+%
+\qquad\qquad\qquad
+%
+\intlongdivision{72344}{7}
+
+\vskip 50pt
+
+\longdivision{.1}{7} \qquad\qquad\qquad \longdivision{000.1}{7}
+%
+\qquad\qquad\qquad
+%
+\intlongdivision{1}{7} % Warning : no_division_occurred
+
+
+\longdivision[20]{1}{49}
+
+\longdivision{1}{49} % Warning : work_stopped_early
+
+\longdivision[20]{1}{97}
+
+\longdivision{1}{97} % Warning : work_stopped_early & division_stopped_early
+
+\longdivision{ 2 147 483.647 }{ 91 474 837 } % Warning : work_stopped_early & division_stopped_early
+
+% \longdivision{1..5}{7} % Error: dividend_invalid
+% \longdivision{2147483.647}{214748367} % Error : divisor_too_large
+% \longdivision{6}{1.5} % Error: divisor_not_int
+% \longdivision{6}{15a} % Error: divisor_invalid
+
+\end{document} 
\ No newline at end of file

Added: trunk/Master/texmf-dist/tex/latex/longdivision/longdivision.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/longdivision/longdivision.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/longdivision/longdivision.sty	2017-02-06 23:37:59 UTC (rev 43159)
@@ -0,0 +1,485 @@
+%% Package: longdivision.sty version 1.0
+%% Author: Hood Chatham
+%% Email: hood at mit.edu
+%% Date: 2/5/2017
+%% License: Latex Project Public License
+
+
+\ProvidesPackage{longdivision}
+\RequirePackage{xparse}
+
+\ExplSyntaxOn
+
+%%
+%% The linked list
+%%
+
+% This token list just stores a reference to the first entry in the linked list
+\tl_new:N \l__longdiv_linkedlist_tl
+\tl_set:Nn\l__longdiv_linkedlist_tl{ \longdiv_linkedlist_next:n { 0 } }
+\int_new:N \l__longdiv_linkedlist_length_int
+
+% Set the next entry to be a no-op so that when expanded the last "null pointer" just disappears
+\cs_new:Nn \longdiv_linkedlist_set_next_do_nothing: {
+    \cs_set_eq:cN { longdiv_linkedlist ~ \int_use:N \l__longdiv_linkedlist_length_int } \prg_do_nothing:
+}
+\longdiv_linkedlist_set_next_do_nothing:
+
+% "pointer" to next element (argument is the element's id)
+\cs_new:Nn \longdiv_linkedlist_next:n { \use:c { longdiv_linkedlist ~ #1 } }
+
+\cs_new:Nn \longdiv_linkedlist_add:n {
+    \cs_set:cpx { longdiv_linkedlist ~ \int_use:N \l__longdiv_linkedlist_length_int}{
+        \exp_not:n{#1} \exp_not:N \longdiv_linkedlist_next:n { \int_eval:n { \l__longdiv_linkedlist_length_int + 1} }
+    }
+    \int_incr:N \l__longdiv_linkedlist_length_int
+    \longdiv_linkedlist_set_next_do_nothing:
+}
+\cs_generate_variant:Nn \longdiv_linkedlist_add:n {f}
+
+% The easy implementation of these next two commands is why I chose the "linked list" format
+
+% Delete last element of list.
+\cs_new:Nn \longdiv_linkedlist_remove_tail: {
+    \int_decr:N \l__longdiv_linkedlist_length_int
+    \longdiv_linkedlist_set_next_do_nothing:
+}
+
+% #1 -- pointer to an element of the list
+% Puts an overline over the rest of the list starting at a certain position. For "repeating decimals".
+\cs_new:Nn \longdiv_linkedlist_put_overline:n {
+    \cs_set:cpx { longdiv_linkedlist ~ #1 }{
+        $\overline { \exp_not:f { \use:c { longdiv_linkedlist ~ #1 } } }$
+    }
+}
+
+
+%%
+%% Entry points
+%%
+
+% \tl_rescan to ignore spaces in input.
+\NewDocumentCommand \longdivision { omm } {
+    \group_begin:
+    \IfNoValueF { #1 } {
+        \int_set:Nn \l__longdiv_max_extra_digits_int { #1 }
+    }
+    \tl_rescan:nn { \ExplSyntaxOn } { \longdiv_start:nn { #2 } { #3 } }
+    \group_end:
+}
+
+% Same as \longdiv[0]{#1}{#2}.
+\NewDocumentCommand \intlongdivision { mm } {
+    \group_begin:
+    \int_set:Nn \l__longdiv_max_extra_digits_int { 0 }
+    \tl_rescan:nn { \ExplSyntaxOn } { \longdiv_start:nn { #1 } { #2 } }
+    \group_end:
+}
+
+% Check input is valid then enter main loop.
+% We use etex \numexpr to ensure that the dividend has no unnecessary leading zeroes and doesn't begin with a decimal point.
+% Note that \int_eval:n wouldn't work here because it inserts a "\relax" token that would not get eaten by \numexpr if
+% #1 contains a decimal point. This "\relax" causes trouble for the division main loop.
+\cs_new:Nn \longdiv_start:nn {
+    \longdiv_check_dividend:n { #1 }
+    \longdiv_check_divisor:n { #2 }
+    % Second copy of #1 is eaten by \longdiv_typeset:nnn to print the dividend
+    \exp_args:Nnnff \longdiv_get_new_digit:nnn { } { #2 } { \the\numexpr 0#1 } { \the\numexpr 0#1  }
+    \longdiv_break_point: { #1 } { #2 }
+}
+
+\cs_set_eq:NN \longdiv_break_point: \use_none:nn
+
+%%
+%% Input checkers
+%%
+
+% Parse through the dividend token by token
+% Check that every token is a digit with the exception of at most one .
+\cs_new:Nn \longdiv_check_dividend:n {
+    \longdiv_check_dividend_before_point:N #1 \q_stop
+}
+
+\cs_new:Nn \longdiv_check_dividend_before_point:N {
+    \token_if_eq_meaning:NNF #1 \q_stop {
+        \token_if_eq_meaning:NNTF #1 . {
+            \longdiv_check_dividend_seen_point:N
+        }{
+            \longdiv_check_dividend_isdigit:N #1
+            \longdiv_check_dividend_before_point:N
+        }
+    }
+}
+
+\cs_new:Nn \longdiv_check_dividend_seen_point:N {
+    \token_if_eq_meaning:NNF #1 \q_stop {
+        \longdiv_check_dividend_isdigit:N #1
+        \longdiv_check_dividend_seen_point:N
+    }
+}
+
+\cs_new:Nn \longdiv_check_dividend_isdigit:N {
+    \bool_if:nF { \token_if_eq_meaning_p:NN #1 0
+      || \token_if_eq_meaning_p:NN #1 1 || \token_if_eq_meaning_p:NN #1 2 || \token_if_eq_meaning_p:NN #1 3
+      || \token_if_eq_meaning_p:NN #1 4 || \token_if_eq_meaning_p:NN #1 5 || \token_if_eq_meaning_p:NN #1 6
+      || \token_if_eq_meaning_p:NN #1 7 || \token_if_eq_meaning_p:NN #1 8 || \token_if_eq_meaning_p:NN #1 9
+    }{
+        \longdiv_error:nwnn { dividend_invalid }
+    }
+}
+
+% Check that there is no ., that it is at most 8 digits, and that the entire argument can get assigned to a count variable
+% There's no way to do this last check in expl3, so I use plaintex \newcount, \afterassignment, and \l__longdiv_temp_int =.
+\newcount \l__longdiv_temp_int
+\cs_new:Nn \longdiv_check_divisor:n {
+    \tl_if_in:nnT { #1 } { . } {
+        \longdiv_error:nwnn { divisor_not_int }
+    }
+    % We have to do the length check before the "validity" check because the "validity" check makes an assignment
+    % which throws a low level error if the number to be assigned is too large.
+    \int_compare:nNnF { \tl_count:n { #1 } } < \c_nine {
+        \longdiv_error:nwnn { divisor_too_large }
+    }
+    % Idea here: if #1 is a valid number, \l__longdiv_temp_int = 0#1 will absorb all of it.
+    % So if there's any left, throw an error. Leading zero ensures that it fails on -1 and
+    % that if #1 starts with some other nondigit character that it won't cause
+    % "Missing number, treated as zero."
+    \afterassignment \longdiv_check_divisor_aux:w
+    \l__longdiv_temp_int = 0 #1 \scan_stop:
+}
+
+\cs_new:Npn \longdiv_check_divisor_aux:w #1 \scan_stop: {
+    \tl_if_empty:nF { #1 } {
+        \longdiv_error:nwnn { divisor_invalid }
+    }
+    \int_compare:nNnT \l__longdiv_temp_int = \c_zero {
+        \longdiv_error:nwnn { divisor_zero }
+    }
+}
+
+% Absorb up to break_point to gracefully quit out of the macro
+\cs_new:Npn \longdiv_error:nwnn #1 #2 \longdiv_break_point: {
+    \msg_error:nnnn { longdivision } { #1 }
+}
+
+% Errors:
+\msg_new:nnn { longdivision } { dividend_invalid } { Dividend ~ '#1' ~ is ~ invalid ~ (\msg_line_context:).}
+\msg_new:nnn { longdivision } { divisor_too_large }
+    { Divisor ~ '#2' ~ is ~ too ~ large ~ (\msg_line_context:). ~ It ~ has ~ \tl_count:n { #2 } ~ digits, ~ but ~ divisors ~ can ~ be ~ at ~ most ~ 9 ~ digits ~ long. }
+\msg_new:nnn { longdivision } { divisor_not_int } { Divisor ~ '#2' ~ is ~ not ~ an ~ integer ~ (\msg_line_context:). }
+\msg_new:nnn { longdivision } { divisor_invalid } { Divisor ~ '#2' ~ is ~ invalid ~ (\msg_line_context:). }
+
+% Warnings:
+\msg_new:nnn { longdivision } { work_stopped_early } { The ~ work ~ display ~ stopped ~ early ~ to ~ avoid ~ running ~ off ~ the ~ page ~ (\msg_line_context:). }
+\msg_new:nnn { longdivision } { division_stopped_early } { The ~ division ~ stopped ~ early ~ to ~ avoid ~ running ~ off ~ the ~ page ~ (\msg_line_context:).}
+\msg_new:nnn { longdivision } { no_division_occurred }
+    { Either ~ the ~ dividend ~ was ~ zero ~ or ~ you ~ used ~ \token_to_str:N \intlongdiv \space and ~ the ~ dividend ~ was ~less ~ than ~ the ~ divisor. ~
+      This ~ isn't ~ a ~ big ~ deal, ~ but ~ the ~ result ~ probably ~ looks ~ silly. }
+
+
+
+%%
+%% Division
+%%
+
+% Core registers
+\bool_new:N \l__longdiv_seen_point_bool
+\bool_new:N \l__longdiv_seen_digit_bool
+\int_new:N \l__longdiv_quotient_int
+\int_new:N \l__longdiv_position_int
+\int_new:N \l__longdiv_point_digit_int
+
+\tl_new:N \l__longdiv_extra_places_tl % This is for storing extra zeroes appended to the dividend
+\dim_new:N \g__longdiv_temp_dim % For measuring the distance to the right side of digits
+
+% These are used to make sure division doesn't run off the page.
+\int_new:N \l__longdiv_extra_digits_int
+\int_new:N \l__longdiv_max_extra_digits_int
+\int_set:Nn \l__longdiv_max_extra_digits_int { 100 } % Infinite (just needs to be greater than max_total_digits_int and max_display_divisions_int)
+\int_const:Nn \c__longdiv_max_total_digits_int { 60 }
+\int_const:Nn \c__longdiv_max_display_divisions_int { 20 }
+\int_new:N \l__longdiv_display_divisions_int
+
+% #1 -- remainder
+% #2 -- divisor
+% #3 -- rest of divits
+\cs_new:Nn \longdiv_get_new_digit:nnn {
+    \tl_if_empty:nTF { #3 } { % Are we out of digits?
+        % If we haven't hit the decimal point add it to the quotient and dividend
+        % Set seen_digit false so that we can remove the decimal point later if it divided evenly or we used \intlongdiv
+        \bool_if:NF \l__longdiv_seen_point_bool {
+            \longdiv_add_point: %
+            \tl_set:Nn \l__longdiv_extra_places_tl { . }
+            \bool_set_false:N \l__longdiv_seen_digit_bool
+        }
+        \longdiv_divide_no_more_digits:nn { #1 } { #2 }
+    }{
+        \longdiv_get_new_digit_aux:nnw { #1 } { #2 } #3;
+    }
+}
+\cs_generate_variant:Nn \longdiv_get_new_digit:nnn {xnn}
+
+\cs_new:Npn \longdiv_get_new_digit_aux:nnw #1 #2 #3 #4;{
+    \token_if_eq_meaning:NNTF #3 . {
+        \longdiv_add_point:
+        \bool_set_true:N \l__longdiv_seen_digit_bool % Prevent this decimal point from being removed later
+        \longdiv_get_new_digit:nnn { #1 } { #2 } { #4 }
+    }{
+        \longdiv_divide:nn { #1 #3 } { #2 } { #4 }
+    }
+}
+
+% Adds a decimal point, with a leading 0 if necessary, and records the current position in \l__longdiv_point_digit_int
+\cs_new:Nn \longdiv_add_point: {
+    \bool_set_true:N \l__longdiv_seen_point_bool
+    \bool_if:NTF \l__longdiv_seen_digit_bool {
+        \longdiv_linkedlist_add:n { . }
+    }{
+        \longdiv_linkedlist_add:n { 0. } % Add a leading zero
+
+    }
+    \int_set_eq:NN \l__longdiv_point_digit_int \l__longdiv_position_int % Record the position of the point
+}
+
+% Divide when we still have more digits.
+% #1 -- thing to divide
+% #2 -- divisor
+% Finds the quotient, adds it to the linked list and to the work token list then recurses.
+\cs_new:Nn \longdiv_divide:nn {
+    %\tl_show:n{#1}
+    \int_set:Nn \l__longdiv_quotient_int { \int_div_truncate:nn { #1 } { #2 } }
+    \bool_if:nF {
+        \int_compare_p:nNn \l__longdiv_quotient_int = \c_zero % If the quotient was zero, we might not have to print it
+        && !\l__longdiv_seen_digit_bool % If no other digits have been printed
+        && !\l__longdiv_seen_point_bool % And we are before the decimal point
+    }{ % Otherwise print it and record that we've seen a digit (all further 0's must be printed)
+        \bool_set_true:N \l__longdiv_seen_digit_bool
+        \longdiv_linkedlist_add:f { \int_use:N \l__longdiv_quotient_int }
+    }
+    \int_incr:N \l__longdiv_position_int
+    \longdiv_divide_record:nn{ #1 }{ #2 }
+    \longdiv_get_new_digit:xnn { \longdiv_remainder:nn { #1 } { #2 } } { #2 }
+}
+
+
+% Divide when we are out of digits.
+% #1 -- remainder from last time (we will add a zero to the end)
+% #2 -- divisor
+% This case is more complicated because we have to check for repeated remainders, and whether to stop
+% though we are certainly after the decimal point so we don't need to check whether we need to print 0's.
+\cs_new:Nn \longdiv_divide_no_more_digits:nn {
+    % If we've seen this remainder before, we're done. Use the appropriate command
+    % to insert the overline, and then typeset everything
+    \cs_if_exist_use:cTF { longdiv_remainders ~ \int_eval:n { #1 } }{ % \int_eval:n to remove leading zero
+        \longdiv_typeset:nnn { #1 } { #2 }
+    }{
+        \bool_if:nTF {
+              \int_compare_p:nNn \l__longdiv_extra_digits_int = \l__longdiv_max_extra_digits_int
+            ||\int_compare_p:nNn \l__longdiv_position_int = \c__longdiv_max_total_digits_int
+        }{
+            \int_compare:nNnT \l__longdiv_position_int = \c__longdiv_max_total_digits_int {
+                \msg_warning:nn { longdivision } { division_stopped_early }
+            }
+            \longdiv_typeset:nnn{#1}{#2}
+        }{
+            % Otherwise, record that we've seen this remainder and the position we're in
+            % In case this is the first digit of the repeated part
+            \cs_set:cpx { longdiv_remainders ~ \int_eval:n { #1 } }{ % \int_eval:n to remove leading zero
+                \exp_not:N \longdiv_linkedlist_put_overline:n { \int_use:N \l__longdiv_linkedlist_length_int }
+            }
+            % Now we have to use #10 everywhere
+            \int_set:Nn \l__longdiv_quotient_int { \int_div_truncate:nn { #10 } { #2 } }
+            \longdiv_linkedlist_add:f { \int_use:N \l__longdiv_quotient_int }
+            \bool_set_true:N \l__longdiv_seen_digit_bool % We've seen a digit after the decimal point, don't need to remove it
+            \int_incr:N \l__longdiv_position_int
+            \int_incr:N \l__longdiv_extra_digits_int
+            \tl_set:Nx \l__longdiv_extra_places_tl { \l__longdiv_extra_places_tl 0 } % Store an extra 0 appended to the dividend
+            \longdiv_divide_record:nn{#10}{#2}
+            \longdiv_divide_no_more_digits:xn { \longdiv_remainder:nn { #10 } { #2 } } { #2 }
+        }
+    }
+}
+\cs_generate_variant:Nn \longdiv_divide_no_more_digits:nn {xn}
+
+% Whenever we see the remainder 0, we're done, and we don't have to put an overline.
+\cs_set:cpn { longdiv_remainders ~ 0}{}
+
+% This command checks if the quotient was zero, and if so preserves the leading zero by avoiding \int_eval:n
+% This is so that e.g, \longdiv{14.1}{7} doesn't screw up
+\cs_new:Nn \longdiv_remainder:nn {
+    \int_compare:nNnTF \l__longdiv_quotient_int = \c_zero
+        { #1 }
+        { \int_eval:n { #1 - \l__longdiv_quotient_int * #2 } }
+}
+
+
+% We're going to store the "work" for the long division in this tl as a series of triples:
+% #1 -- number of digits we've processed so far (for positioning subtractions and determining if point should be added)
+% #2 -- old remainder (thing to subtract from)
+% #3 -- quotient * divisor (thing to subtract)
+\tl_new:N \l__longdiv_work_tl
+\cs_new:Nn \longdiv_divide_record:nn{
+    \int_compare:nNnTF \l__longdiv_display_divisions_int < \c__longdiv_max_display_divisions_int {
+        \int_compare:nNnF \l__longdiv_quotient_int = \c_zero { % If the quotient was zero, nothing needs to be typeset
+            \tl_set:Nx \l__longdiv_work_tl {
+                \l__longdiv_work_tl
+                    { \int_use:N \l__longdiv_position_int } { #1 } { \int_eval:n { \l__longdiv_quotient_int * #2 } }
+            }
+            \int_incr:N \l__longdiv_display_divisions_int
+        }
+    }{
+        \int_compare:nNnT \l__longdiv_display_divisions_int = \c__longdiv_max_display_divisions_int {
+            \int_compare:nNnF \l__longdiv_quotient_int = \c_zero {
+                \tl_set:Nx \l__longdiv_work_tl {
+                    \l__longdiv_work_tl
+                        { \int_use:N \l__longdiv_position_int } { #1 } { \int_eval:n { \l__longdiv_quotient_int * #2 } }
+                        \exp_not:N \longdiv_typeset_work_last:nn { \int_use:N \l__longdiv_position_int } { \int_eval:n { #1 - \l__longdiv_quotient_int * #2 } }
+                }
+                \int_incr:N \l__longdiv_display_divisions_int
+                \msg_warning:nn { longdivision } { work_stopped_early }
+            }
+        }
+    }
+}
+
+%%
+%% Typesetting
+%%
+
+
+% \l__longdiv_linkedlist_tl -- quotient
+% #1 -- remainder
+% #2 -- divisor
+% #3 -- dividend
+\cs_new:Nn \longdiv_typeset:nnn {
+    % If we haven't seen any new digits since adding a terminal decimal point, delete it.
+    \bool_if:NF \l__longdiv_seen_digit_bool { \longdiv_linkedlist_remove_tail: }
+
+    #2\,\begin{tabular}[b]{@{}r@{}}
+    \int_compare:nNnTF \l__longdiv_linkedlist_length_int = \c_zero
+        { 0 }
+        { \l__longdiv_linkedlist_tl }
+    \\\hline
+    \big)\begin{tabular}[t]{@{}l@{}}
+    % Likewise we don't want to add a trailing decimal point to the dividend if it divided evenly
+    #3 \bool_if:NT \l__longdiv_seen_digit_bool { \l__longdiv_extra_places_tl } \\
+    \longdiv_typeset_work:n { #1 }
+    \end{tabular}
+    \end{tabular}
+}
+
+% Iterate through the division "work" and typeset it
+\cs_new:Nn \longdiv_typeset_work:n {
+    \tl_if_empty:NTF \l__longdiv_work_tl {
+        \msg_warning:nn { longdivision } { no_division_occurred }
+    }{
+        \exp_after:wN \longdiv_typeset_work_first:nnn \l__longdiv_work_tl
+        \int_compare:nNnT \l__longdiv_display_divisions_int < \c__longdiv_max_display_divisions_int {
+            \exp_args:No \longdiv_typeset_work_last:nn { \int_use:N \l__longdiv_position_int } { #1 }
+        }
+    }
+}
+
+% #1 -- digits in to the right side of the numbers we are writing
+% #2 -- remainder from last time with new digits added to the right
+% #3 -- quotient * divisor
+% _first only typesets quotient * divisor and the line
+% _rest typesets result from last time, quotient * divisor and the line
+% _last only typesets the remainder from last time
+\cs_new:Nn \longdiv_typeset_work_first:nnn {
+    \longdiv_typeset_setwidth:n { #1 }
+    \hspace{\g__longdiv_temp_dim}
+    \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #3 } }
+    \\\longdiv_rule:nn{#1}{#3}
+    \peek_meaning:NT \bgroup {
+        \longdiv_typeset_work_rest:nnn
+    }
+}
+
+\cs_new:Nn \longdiv_typeset_work_rest:nnn {
+    \longdiv_typeset_setwidth:n { #1 }
+    \hspace{\g__longdiv_temp_dim}
+    \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #2 } }
+    \\
+    \hspace{\g__longdiv_temp_dim}
+    \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #3 } }
+    \\\longdiv_rule:nn{#1}{#3}
+    \peek_meaning:NT \bgroup {
+        \longdiv_typeset_work_rest:nnn
+    }
+}
+
+% #1 -- digits in to the right side of the numbers we are writing
+% #2 -- remainder from last time with new digits added to the right
+\cs_new:Npn \longdiv_typeset_work_last:nn #1 #2 {
+    \longdiv_typeset_setwidth:n { #1 }
+    \hspace{\g__longdiv_temp_dim}
+    \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #2 } }
+}
+
+% Set \g__longdiv_temp_dim equal to digitwidth * number of digits
+% If we are past the decimal point, add  \c__longdiv_pointwidth_dim
+\cs_new:Nn \longdiv_typeset_setwidth:n {
+    \dim_gset:Nn \g__longdiv_temp_dim { #1\c__longdiv_digitwidth_dim }
+    \int_compare:nNnT \l__longdiv_point_digit_int < {#1} {
+        \dim_gadd:Nn \g__longdiv_temp_dim \c__longdiv_pointwidth_dim
+    }
+}
+
+% If the number ends after the decimal point ( #1 > \l__longdiv_point_digit_int )
+% and start before it ( #1 - length(#2) < \l__longdiv_point_digit_int) insert a
+% decimal point in the appropriate position of #2. Otherwise just return #2
+\cs_new:Nn \longdiv_insert_point_ifneeded:nn {
+    \bool_if:nTF {
+          \int_compare_p:nNn  { #1 }                      > \l__longdiv_point_digit_int
+        && \int_compare_p:nNn { #1 - \tl_count:n { #2 } } < \l__longdiv_point_digit_int
+    }{
+        \longdiv_insert_point:nn {\int_eval:n{\l__longdiv_point_digit_int - #1 + \tl_count:n { #2 }}} { #2 }
+    }{
+        #2
+    }
+}
+
+% Walk #1 digits across #2 and then insert a decimal point.
+\cs_new:Nn \longdiv_insert_point:nn {
+    \longdiv_insert_point_aux:oN { #1 } #2
+}
+
+\cs_new:Nn \longdiv_insert_point_aux:nN {
+    \int_compare:nNnTF { #1 } = \c_zero {
+        .#2
+    }{
+        #2 \longdiv_insert_point_aux:oN { \int_eval:n { #1 - 1 } }
+    }
+}
+\cs_generate_variant:Nn \longdiv_insert_point_aux:nN {oN}
+
+
+% Okay, this is another section where we are adulterated with plaintex stuff.
+% It would be easy to reimplement \settowidth, but \hrule and \noalign have no
+% expl3 name anyways. Since I only use these dim variables with \settowidth, I declare
+% them with \newdimen rather than \dim_new:N
+\newdimen   \c__longdiv_digitwidth_dim
+\settowidth \c__longdiv_digitwidth_dim { 0 }
+\newdimen   \c__longdiv_pointwidth_dim
+\settowidth \c__longdiv_pointwidth_dim { . }
+\newdimen   \l__longdiv_tempwidth_dim
+
+\cs_new:Nn \longdiv_rule:nn {
+    \noalign {
+        \settowidth \l__longdiv_tempwidth_dim { #2 }
+        % Check whether the decimal point occurred in the middle of the current number
+        % because if so, it's longer by pointwidth.
+        \bool_if:nT {
+              \int_compare_p:nNn  { #1 }                      > \l__longdiv_point_digit_int
+            && \int_compare_p:nNn { #1 - \tl_count:n { #2 } } < \l__longdiv_point_digit_int
+        }{
+            \dim_add:Nn \l__longdiv_tempwidth_dim \c__longdiv_pointwidth_dim
+        }
+        \box_move_right:nn { \g__longdiv_temp_dim - \l__longdiv_tempwidth_dim } {
+            \vbox:n { \hrule width \l__longdiv_tempwidth_dim }
+        }
+    }
+}
+
+\ExplSyntaxOff

Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2017-02-06 23:37:17 UTC (rev 43158)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2017-02-06 23:37:59 UTC (rev 43159)
@@ -369,7 +369,8 @@
     lithuanian liturg lkproof lm lm-math lmake lobster2
     locality localloc logbox logical-markup-utils logicproof logicpuzzle
     logpap logreq lollipop
-    longfbox longfigure longnamefilelist loops lpform lpic lplfitch lps
+    longdivision longfbox longfigure longnamefilelist loops
+    lpform lpic lplfitch lps
     lroundrect lsc
     lshort-bulgarian lshort-chinese lshort-czech lshort-dutch lshort-english
     lshort-estonian lshort-finnish lshort-french lshort-german lshort-italian

Modified: trunk/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc	2017-02-06 23:37:17 UTC (rev 43158)
+++ trunk/Master/tlpkg/tlpsrc/collection-mathscience.tlpsrc	2017-02-06 23:37:59 UTC (rev 43159)
@@ -84,6 +84,7 @@
 depend karnaugh-map
 depend karnaughmap
 depend logicproof
+depend longdivision
 depend lpform
 depend lplfitch
 depend lstbayes

Added: trunk/Master/tlpkg/tlpsrc/longdivision.tlpsrc
===================================================================


More information about the tex-live-commits mailing list