diff options
author | Karl Berry <karl@freefriends.org> | 2020-05-11 20:48:13 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-05-11 20:48:13 +0000 |
commit | 0e1ee2e226e159a60e8f3c25f41bfbf1ed10679c (patch) | |
tree | c033586537dec31ec6fc32304736fd89a004d40a /Master | |
parent | eb00832c57337e4a212023733271ce2371ba231b (diff) |
longdivision (11may20)
git-svn-id: svn://tug.org/texlive/trunk@55103 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/latex/longdivision/README.md | 31 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/longdivision/longdivision_manual.pdf | bin | 135922 -> 155728 bytes | |||
-rw-r--r-- | Master/texmf-dist/doc/latex/longdivision/longdivision_manual.tex | 88 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/longdivision/longdivision.sty | 956 |
4 files changed, 692 insertions, 383 deletions
diff --git a/Master/texmf-dist/doc/latex/longdivision/README.md b/Master/texmf-dist/doc/latex/longdivision/README.md index e459c12ca8f..db6a6469aa1 100644 --- a/Master/texmf-dist/doc/latex/longdivision/README.md +++ b/Master/texmf-dist/doc/latex/longdivision/README.md @@ -1,8 +1,8 @@ -longdivision v1.1.0 +longdivision v1.2.0 ======================== Author: Hood Chatham Email: hood@mit.edu -Date: 2019-03-24 +Date: 2020-05-09 Description: License: All files have the Latex Project Public License. Files: @@ -29,7 +29,11 @@ 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). -See the package manual for more information. +See the package manual for more information. To compile the manual, you need +the file pgfmanual-en-macros.tex from the tikz manual. I am not allowed to +include this file on the CTAN repositiory due to rules against file duplication, +but you can find it on github: +https://github.com/hoodmane/longdivision/blob/master/pgfmanual-en-macros.tex Email me at hood@mit.edu to submit bug reports, request new features, etc. The current development copy is hosted at https://github.com/hoodmane/longdivision. @@ -38,16 +42,31 @@ The current development copy is hosted at https://github.com/hoodmane/longdivisi Changelog: ========== -## [1.1.0] (2018-10-08) +## [1.2.0] (2020-05-09) +### Added: +- An option to control the decimal separator +- Options to specify "digit separator" and "digit group length" +- A "separators in work" option to put spaces rather than punctuation in the work +- Change the division sign in "german style" long division + ### Fixed: -- If the "\longdivision" command is in math mode, the numbers are typeset in math mode too (reported by Yu-Tsiang Tai). -- The "\longdivision" command now can handle macros as arguments (as suggested by Mike Jenck). +- Math mode usage used to be inconsistent. Now if not used in math mode, + typesetting is consistently not in math mode, if used in math mode it is + consistently in math mode. +- Major improvements to typesetting engine should allow changes in the future to be less painful. +- A few deprecated expl3 commands have been replaced (thanks to a pull request from Phelype Oleinik). + +## [1.1.0] (2018-10-08) ### Added: - Multiple typesetting styles - Multiple styles for indicating a repeating decimal - Typesetting partial long division (as suggested by Cameron McLeman). +### Fixed: +- If the "\longdivision" command is in math mode, the numbers are typeset in math mode too (reported by Yu-Tsiang Tai). +- The "\longdivision" command now can handle macros as arguments (as suggested by Mike Jenck). + ## [1.0.0] (2017-02-05) diff --git a/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.pdf b/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.pdf Binary files differindex 64a9bee6c52..f64df8e2f92 100644 --- a/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.pdf +++ b/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.pdf diff --git a/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.tex b/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.tex index c4f23a9fbc9..24e39282480 100644 --- a/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.tex +++ b/Master/texmf-dist/doc/latex/longdivision/longdivision_manual.tex @@ -1,8 +1,11 @@ \documentclass{ltxdoc} -\def\version{Version 1.1.0} +\def\version{Version 1.2.0} +\let\ifluatex\relax +\usepackage{ifluatex} \usepackage[a4paper,left=2.25cm,right=2.25cm,top=2.5cm,bottom=2.5cm,nohead]{geometry} \usepackage{longdivision} + \usepackage{tikz} \usepackage[documentation]{tcolorbox} \usepackage{etoolbox} @@ -98,7 +101,7 @@ \date{\version\\\today} \maketitle -The \longdivname\ package defines two main commands: |\longdivision| and |\intlongdivision|. The usage for both is |\longdivision[|\meta{options}|]|\marg{dividend}\marg{divisor}. The difference is that |\longdivision| divides until the remainders repeat or the quotient has too many digits to fit the page, whereas |\intlongdivision| does integer division and leaves the remainder. The command |\longdivisionkeys|\marg{options} is also defined to set default options. At most 20 division steps worth of work will be displayed and at most 60 digits worth of division output will be produced. Thanks to Mike Jenck, Cameron McLeman, and Yu-Tsung Tai for emailing me with bug reports and feature requests. +The \longdivname\ package defines two main commands: |\longdivision| and |\intlongdivision|. The usage for both is |\longdivision[|\meta{options}|]|\marg{dividend}\marg{divisor}. The difference is that |\longdivision| divides until the remainders repeat or the quotient has too many digits to fit the page, whereas |\intlongdivision| does integer division and leaves the remainder. The command |\longdivisionkeys|\marg{options} is also defined to set default options. At most 20 division steps worth of work will be displayed and at most 60 digits worth of division output will be produced. Thanks to Mike Jenck, Ben McKay, Cameron McLeman, Phelype Oleinik, Maximilian Schmidt, and Yu-Tsung Tai for bug reports and feature requests. Here is an example usage: @@ -114,8 +117,8 @@ These commands have several key-value options: This key determines the maximum amount of ``extra'' zeroes to add to the end of the dividend in the process of division -- if the quotient has more digits before it repeats, the division will just stop. This is only an option for |\longdivision|, the command |\intlongdivision|\marg{dividend}\marg{divisor} is equivalent to |\longdivision[max extra digits=0]|\marg{dividend}\marg{divisor}. For brevity, this option has the short form where just the value is provided: |\longdivision[2]|\marg{dividend}\marg{divisor} is the same as |\longdivision[max extra digits=2]|\marg{dividend}\marg{divisor}. \begin{tcblisting}{} -\longdivision[max extra digits = 2]{10.0}{7} \quad -\longdivision[1]{10.0}{7} +\longdivision[max extra digits = 1]{14.1}{7} \quad +\longdivision[2]{14.1}{7} \end{tcblisting} \end{key} @@ -123,26 +126,28 @@ This key determines the maximum amount of ``extra'' zeroes to add to the end of \begin{key}{stage = \meta{nonnegative integer}} This controls how many steps worth of division to do. Thanks to Cam McLeman for suggesting this feature. \begin{tcblisting}{} -\longdivision[stage=0]{1}{7} \quad -\longdivision[stage=1]{1}{7} \quad -\longdivision[stage=2]{1}{7} \quad -\longdivision[stage=3]{1}{7} \quad -\longdivision[stage=4]{1}{7} \quad -\longdivision[stage=5]{1}{7} \quad -\longdivision[stage=6]{1}{7} +\longdivision[stage=0]{5.3}{37} \quad +\longdivision[stage=1]{5.3}{37} \quad +\longdivision[stage=2]{5.3}{37} \quad +\longdivision[stage=3]{5.3}{37} \quad +\longdivision[stage=4]{5.3}{37} \end{tcblisting} \end{key} -\begin{key}{style = \meta{style}} +\begin{key}{style = \meta{style} (initially standard)} Control the style for typesetting the result of long division. The options are |default|, |standard|, |tikz|, or |german|. The option |default| is the same as |tikz| if \tikzname\ is loaded and otherwise is the same as |standard|. You probably should load \tikzname\ because the \tikzname\ version looks significantly better. If you use this option, you'll probably want to set the style once and for all in your preamble with |\longdivisionkeys{style=|\meta{style}|}|. \begin{tcblisting}{} \intlongdivision[style = tikz ]{100.0}{13} \quad \intlongdivision[style = standard]{100.0}{13} \quad \intlongdivision[style = german ]{100.0}{13} \end{tcblisting} -You can define your own typesetting style by saying |\longdiv_define_style:nn|\marg{style name}\marg{code}. This can use the commands |\longdivdividend| which contains the dividend, |\longdivdivisor| which contains the divisor, |\longdivquotient| which contains the quotient, and |\longdivwork:| which contains the |division work|. For instance, a simplified version of the |german| style is: +You can define your own style with |\longdivisiondefinestyle|\marg{style name}\marg{code}. +In the |\marg{code}| you can use the commands |\longdivdivisor| which contains the divisor, |\longdivdividend| which contains the dividend, +|\longdivquotient| which contains the quotient, |\longdivwork| which contains the division work +and |\longdivremainder| which contains the remainder. +For instance, a simplified version of the |german| style is: \begin{tcblisting}{} -\longdivdefinestyle{my style}{% +\longdivisiondefinestyle{my style}{% \begin{tabular}{@{}l@{}} \longdivdividend : \, \longdivdivisor \, = \longdivquotient \\ \longdivwork @@ -153,8 +158,8 @@ You can define your own typesetting style by saying |\longdiv_define_style:nn|\m Send me an email if you cannot figure out how to make a style to your liking. \end{key} -\begin{key}{repeating decimal style = \meta{style}} -Control the way that repeating decimals are typeset. The options are |overline|, |dots|, |dots all|, |parentheses|, or |none|. The default is |overline|. The |parentheses| style creates ugly spacing problems and the |dots| style is insufficiently visible, so the |overline| style is the best. If you use this option, you'll probably want to set the style once and for all in your preamble with |\longdivisionkeys{recurring decimal style=|\meta{style}|}| |\longdivisionkeys{style=|\meta{style}|}|. Like the |style| key, this is designed to be extensible. However, the process of creating new |repeating decimal style|s is a bit involved. Send me an email if you want a new |repeating decimal style|. +\begin{key}{repeating decimal style = \meta{style} (initially overline)} +Control the way that repeating decimals are typeset. The options are |overline|, |dots|, |dots all|, |parentheses|, or |none|. The default is |overline|. The |parentheses| style creates ugly spacing problems and the |dots| style is insufficiently visible, so the |overline| style is the best. If you use this option, you'll probably want to set the style once and for all in your preamble with |\longdivisionkeys{recurring decimal style=|\meta{style}|}|. Like the |style| key, this is designed to be extensible. However, the process of creating new |repeating decimal style|s is a bit involved. Send me an email if you want a new |repeating decimal style|. \begin{tcblisting}{} \longdivision[repeating decimal style = overline ]{5.3}{37} \quad \longdivision[repeating decimal style = dots ]{5.3}{37} \quad @@ -163,4 +168,55 @@ Control the way that repeating decimals are typeset. The options are |overline|, \longdivision[repeating decimal style = none ]{5.3}{37} \end{tcblisting} \end{key} + + +\begin{key}{decimal separator = \meta{separator character} (initially .)} +Control the character used to indicated the decimal point. Most people want this to be a period or a comma. The default is a period. Note that this changes the decimal separator BOTH in the input and in the output. If you set the decimal separator to a comma and then use a period in the input, it will throw an error (though this could be inconvenient for people -- if this behavior causes you trouble, email me and I can fix it). +If you want to use the comma decimal separator, I recommend saying |\longdivisionkeys{decimal separator = {,}}| in your preamble. +\begin{tcblisting}{} +\longdivision[decimal separator = {.}]{2.1}{3} \quad +\longdivision[decimal separator = {,}]{2,1}{3} +\end{tcblisting} +\end{key} + +\begin{key}{digit separator = \meta{separator character} (initially none)} +Control the character used to separate groups of digits in the output. +By default digit groups have length 3, but that can be configured with the |digit group length| key. +%The digit separator will also be deleted from input strings. +If value is empty, then no separator is used. +Most people want this to be a period or a comma. +Note that this changes the decimal separator BOTH in the input and in the output. If you set the decimal separator to a comma and then use a period in the input, it will throw an error. +\begin{tcblisting}{} +\longdivisionkeys{digit group length = 2} +\longdivision[digit separator = {,}]{5}{7} \quad +\longdivision[digit separator = {.}, decimal separator = {,}]{5}{7} +\longdivision[digit separator = { }]{5}{7} +\longdivision[digit separator = {_}]{5}{7} +\end{tcblisting} +\end{key} + +\begin{key}{digit group length = \meta{integer} (initially 3)} +Specify how often to include a digit separator. Does nothing without the |digit separator| key. +\begin{tcblisting}{} +\longdivision[digit group length = 2, digit separator = {,}]{5}{7} \quad +\longdivision[digit group length = 3, digit separator = { }]{5}{7} \quad +\longdivision[digit group length = 4, digit separator = {_}]{5}{7} +\end{tcblisting} +\end{key} + +\begin{key}{separators in work = \meta{bool} (initially true)} +Specifies whether to include the decimal and digit separators in division work. When this is false, |\longdivision| will leave a space instead so that the digits are aligned correctly. \begin{tcblisting}{} +\longdivision[separators in work = true ]{14.1}{3} \quad +\longdivision[separators in work = false]{14.1}{3} +\end{tcblisting} +\end{key} + +\begin{key}{german division sign = \meta{division sign} (initially :)} +\begin{tcblisting}{} +\longdivisionkeys{style = german} +\longdivision[german division sign = $\,\div\,$ ]{14.1}{3} \quad +\longdivision[german division sign = : ]{14.1}{3} +\end{tcblisting} +\end{key} + \end{document} diff --git a/Master/texmf-dist/tex/latex/longdivision/longdivision.sty b/Master/texmf-dist/tex/latex/longdivision/longdivision.sty index 98349704fe5..d749bab70e1 100644 --- a/Master/texmf-dist/tex/latex/longdivision/longdivision.sty +++ b/Master/texmf-dist/tex/latex/longdivision/longdivision.sty @@ -1,7 +1,7 @@ -%% Package: longdivision.sty version 1.0 +%% Package: longdivision.sty version 1.2.0 %% Author: Hood Chatham %% Email: hood@mit.edu -%% Date: 2/5/2017 +%% Date: 2020-05-09 %% License: Latex Project Public License @@ -10,18 +10,23 @@ \ExplSyntaxOn - +% % Core registers +% \bool_new:N \l__longdiv_mathmode_bool -\bool_new:N \l_longdiv_repeating_decimal_bool \bool_new:N \l__longdiv_added_point_bool \bool_new:N \l__longdiv_seen_point_bool \bool_new:N \l__longdiv_seen_digit_bool \bool_new:N \l__longdiv_stopped_early_stage_bool \int_new:N \l__longdiv_quotient_int \int_new:N \l__longdiv_position_int -\int_new:N \l__longdiv_point_digit_int -\int_new:N \l__longdiv_repeat_digit_int +\int_new:N \l__longdiv_point_digit_dividend_int +\int_new:N \l__longdiv_point_digit_quotient_int +\int_new:N \l__longdiv_repeat_digit_int % How many digits after the decimal point does repitition start (so in 1/9 will be 0) +\int_set:Nn \l__longdiv_repeat_digit_int { 100 } +\int_new:N \l__longdiv_digit_group_length + +\int_set:Nn \l__longdiv_digit_group_length 3 \dim_new:N \g__longdiv_temp_dim % For measuring the distance to the right side of digits @@ -36,29 +41,100 @@ \int_const:Nn \c__longdiv_max_display_divisions_int { 20 } \int_new:N \l__longdiv_display_divisions_int +\tl_new:N \l__longdiv_remainder_tl +\tl_new:N \l__longdiv_divisor_tl +\tl_new:N \l__longdiv_dividend_tl +\tl_new:N \l__longdiv_quotient_tl + +% % Key-value arguments +% \cs_new:Npn \longdivisionkeys #1 { \keys_set:nn { longdivision } { #1 } } \keys_define:nn { longdivision } { stage .int_set:N = \l__longdiv_digits_requested_int, - max~extra~digits .int_set:N = \l__longdiv_max_extra_digits_int, + max ~ extra ~ digits .int_set:N = \l__longdiv_max_extra_digits_int, unknown .code:n = { - %\def\temp{#1}\show\temp - \int_set:Nn \l__longdiv_max_extra_digits_int { \l_keys_key_tl } - } + \longdiv_if_int:nTF {\tl_use:N \l_keys_key_tl}{ + \int_set:Nn \l__longdiv_max_extra_digits_int { \l_keys_key_tl } + }{ + \msg_error:nnx { longdivision } { unknown_key } { \tl_use:N \l_keys_key_tl } + } + }, + german ~ division ~ sign .code:n = { + \cs_set:Nn \longdiv_german_division_sign: { #1 } + }, + decimal ~ separator .code:n = { + \tl_if_single:nTF { #1 } { + \longdiv_if_digit:nTF { #1 } { + \msg_error:nnn { longdivision } { decimal_separator_is_digit } { #1 } + } { + \cs_set:Nn \longdiv_decimal_separator: { #1 } + } + }{ + \msg_error:nnn { longdivision } { decimal_separator_not_single } { #1 } + } + }, + digit ~ separator .code:n = { + \cs_if_exist_use:cF { longdiv_digit_separator ~ \detokenize{#1} }{ + \cs_set_protected:Nn \longdiv_digit_separator: { #1 } + } + }, + digit ~ group ~ length .int_set:N = \l__longdiv_digit_group_length, + separators ~ in ~ work .bool_set:N = \l__longdiv_separators_in_work_bool +} + +\cs_set:cpn { longdiv_digit_separator ~ _ }{ + \cs_set_protected:Nn \longdiv_digit_separator: { \texttt{\detokenize{_}} } +} + +% We want to test for decimal separator later with \ifx / \token_if_eq_meaning:NN so we use \let to define the decimal separator. +% The digit separator is only important currently in the output, so we can use \def for that. +% TODO: ignore digit separator in input. +\cs_new:Nn \longdiv_decimal_separator: { . } +\cs_new:Nn \longdiv_digit_separator: { } +\bool_set_true:N \l__longdiv_separators_in_work_bool + + +\newcount\longdiv@tempcount +\cs_new:Npn \longdiv_if_int:nTF #1 { + \afterassignment \longdiv_checkint_aux:w + % Why would I use $$ as a delimiter? Needs to be unexpandable and unlikely to show up in #1. + % I think \relax / \scan_stop: doesn't work because \int_eval:w will absorb a relax. + \longdiv@tempcount = \int_eval:w 0 #1 $$ +} + +\cs_new:Npn \longdiv_checkint_aux:w #1 $$ { % Picked up down here + \tl_if_empty:nTF { #1 } } \cs_new:Nn \longdiv_register_repeating_decimal_style_choices:n { \keys_define:nn { longdivision } { - repeating~decimal~style .choices:nn = + repeating ~ decimal ~ style .choices:nn = { #1 } { - \cs_set_eq:Nc \longdiv_linkedlist_indicate_repeating_decimal:n { longdiv_linkedlist_indicate_repeating_decimal_##1:n } + \cs_set_eq:Nc \longdiv_indicate_repeating_decimal:n { longdiv_indicate_repeating_decimal_##1:n } + \cs_if_exist:cT { longdiv_indicate_repeating_decimal_ ##1 _skip_begin: } { + \cs_set_eq:Nc \longdiv_indicate_repeating_decimal_skip_begin: { longdiv_indicate_repeating_decimal_ ##1 _skip_begin: } + } + \cs_if_exist:cT { longdiv_indicate_repeating_decimal_ ##1 _skip_end: } { + \cs_set_eq:Nc \longdiv_indicate_repeating_decimal_skip_end: { longdiv_indicate_repeating_decimal_ ##1 _skip_end: } + } } } } +% In the annoying and ugly "parentheses" repeating decimal setting, the repeating indicators take up space. +% \longdiv_indicate_repeating_decimal_skip_begin: and \longdiv_indicate_repeating_decimal_skip_end: are supposed to measure the amount +% of space taken up. For all the other settings, they are just empty. +\cs_new:Nn \longdiv_indicate_repeating_decimal_skip_begin: { } +\cs_new:Nn \longdiv_indicate_repeating_decimal_skip_end: { } +% This is a no-op except in the parentheses setting. +\cs_new:Nn \longdiv_indicate_repeating_decimal_phantom:n { \longdiv_indicate_repeating_decimal_skip_begin: #1 \longdiv_indicate_repeating_decimal_skip_end: } +\cs_new:Nn \longdiv_indicate_repeating_decimal_dividend:n { \longdiv_indicate_repeating_decimal_phantom:n { #1 } } +\cs_new:Nn \longdiv_indicate_repeating_decimal_quotient:n { \longdiv_indicate_repeating_decimal:n { #1 } } + \cs_new:Nn \longdiv_register_style_choices:n { \keys_define:nn { longdivision } { style .choices:nn = @@ -76,80 +152,108 @@ \cs_new:cpn { longdiv_typeset_main_ #1 :} { #2 } \longdiv_register_style_choices:n { #1 } } -\let \longdivdefinestyle \longdiv_define_style:nn +\let \longdivisiondefinestyle \longdiv_define_style:nn -%% -%% 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 +% Errors: +\group_begin: +\char_set_catcode_space:N\ % Using ~ in the messages is annoying, so let's restore the catcode of space for the meantime +\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:).} +\msg_new:nnn {longdivision} {unknown_key} {Unknown key '#1'. (\msg_line_context:).} +\msg_new:nnn {longdivision} {decimal_separator_not_single} {Decimal separator '#1' should be a single token. (\msg_line_context:).} +\msg_new:nnn {longdivision} {decimal_separator_is_digit} {Decimal separator '#1' is a digit which is not allowed. (\msg_line_context:).} -% 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: +% 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.} +\msg_new:nnn {longdivision} {no_tikz} {You requested "style~=~tikz" but tikz has not been loaded. Falling back to "style~=~standard".} +\group_end: -% "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{ \longdiv_linkedlist_element: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_new_eq:NN \longdiv_linkedlist_element:n \use:n -\cs_generate_variant:Nn \longdiv_linkedlist_add:n { f } -% The easy implementation of remove_tail and the \longdiv_linkedlist_indicate_repeating_decimal 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: -} %% %% Entry points %% -% \tl_rescan to ignore spaces in input. \NewDocumentCommand \longdivision { omm } { \group_begin: \IfNoValueF { #1 } { \keys_set:nn { longdivision } { #1 } } - \tl_rescan:nn { \ExplSyntaxOn } { \longdiv_start:xx { #2 } { #3 } } + \longdiv_start:xx { #2 } { #3 } \group_end: } -% Same as \longdiv[0]{#1}{#2}. +% Same as \longdiv[options, 0]{#1}{#2}. \NewDocumentCommand \intlongdivision { omm } { \group_begin: \IfNoValueF { #1 } { \keys_set:nn { longdivision } { #1 } } \int_set:Nn \l__longdiv_max_extra_digits_int { 0 } - \tl_rescan:nn { \ExplSyntaxOn } { \longdiv_start:xx { #2 } { #3 } } + \longdiv_start:xx { #2 } { #3 } \group_end: } +\cs_generate_variant:Nn \tl_remove_all:Nn { No } + +% We need \longdiv_decimal_separator: to be \def'd so that we can expand it for use with tl_remove_all (in prepare_dividend) +% but we also want to test for the decimal separator with \token_if_eq_meaning:NN (in \longdiv_if_token_is_decimal_separator:N) +\cs_new:Nn \longdiv_store_decimal_separator_token: { + \exp_last_unbraced:NNo \cs_set_eq:NN \longdiv_decimal_separator_token: \longdiv_decimal_separator: +} + +\cs_new:Nn \longdiv_start:nn { + \longdiv_store_decimal_separator_token: + \tl_set:Nn \l_tmpa_tl {#1} + \tl_set:Nn \l_tmpb_tl {#2} + % Remove spaces from arguments (we used to do this by setting space to ignore and using \tl_rescan but that is a bit gauche). + \tl_remove_all:Nn \l_tmpa_tl { ~ } + \tl_remove_all:Nn \l_tmpb_tl { ~ } + % TODO: Remove digit separators from inputs (dummied out because I didn't feel like handling _ case) + % \tl_if_empty:oF \longdiv_digit_separator: { + % \tl_remove_all:No \l_tmpa_tl { \longdiv_digit_separator: } + % \tl_remove_all:No \l_tmpb_tl { \longdiv_digit_separator: } + % } + \longdiv_add_leading_zero_if_necessary:N \l_tmpa_tl + + \longdiv_start_i:xx + { \tl_use:N \l_tmpa_tl } + { \tl_use:N \l_tmpb_tl } +} +\cs_generate_variant:Nn \longdiv_start:nn { xx } + + +\cs_generate_variant:Nn \tl_if_eq:nnT { xnT } +\cs_new:Nn \longdiv_add_leading_zero_if_necessary:N { + \tl_if_eq:xnT { \tl_head:N { #1 } } { . } { + \tl_put_left:Nn \l_tmpa_tl { 0 } + } +} + % Check input is valid then enter main loop. % We use \int_eval:w 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 } +\cs_new:Nn \longdiv_start_i:nn { + \longdiv_if_decimal_number:nF { #1 } { + \longdiv_error:nwnn { dividend_invalid } + } \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 } { \int_eval:w 0#1 } { \int_eval:w 0#1 } + \tl_set:Nn \l__longdiv_dividend_tl { #1 } + \tl_set:Nn \l__longdiv_divisor_tl { #2 } + \longdiv_get_new_digit:nnn { } { #2 } { #1 } \longdiv_break_point: { #1 } { #2 } } -\cs_generate_variant:Nn \longdiv_start:nn { xx } +\cs_generate_variant:Nn \longdiv_start_i:nn { xx } \cs_new_eq:NN \longdiv_break_point: \use_none:nn @@ -157,42 +261,70 @@ %% Input checkers %% +\prg_new_conditional:Nnn \longdiv_if_token_is_decimal_separator:N { TF } { + \token_if_eq_meaning:NNTF #1 \longdiv_decimal_separator_token: { + \prg_return_true: + }{ + \prg_return_false: + } +} + + % 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 +\prg_new_conditional:Nnn \longdiv_if_decimal_number:n { F } { + \longdiv_if_decimal_number_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 +\cs_new:Nn \longdiv_if_decimal_number_before_point:N { + \token_if_eq_meaning:NNTF #1 \q_stop { + \prg_return_true: + }{ + \longdiv_if_token_is_decimal_separator:NTF #1 { + \longdiv_if_decimal_number_seen_point:N }{ - \longdiv_check_dividend_isdigit:N #1 - \longdiv_check_dividend_before_point:N + \longdiv_if_digit:nF { #1 }{ + \prg_return_false: + \use_none_delimit_by_q_stop:w + } + \longdiv_if_decimal_number_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_if_decimal_number_seen_point:N { + \token_if_eq_meaning:NNTF #1 \q_stop { + \prg_return_true: + }{ + \longdiv_if_digit:nF { #1 }{ + \prg_return_false: + \use_none_delimit_by_q_stop:w + } + \longdiv_if_decimal_number_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 } - } +\prg_new_conditional:Nnn \longdiv_if_digit:n { T, F, TF, p } { + \bool_lazy_and:nnTF + { \tl_if_single_p:n { #1 } } + {\bool_lazy_any_p:n{ + { \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 } + }} + { \prg_return_true: } + { \prg_return_false: } } % 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 =. +% There's no slick 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 } { . } { @@ -200,7 +332,7 @@ } % 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 { + \int_compare:nNnF { \tl_count:n { #1 } } < 9 { \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. @@ -215,7 +347,7 @@ \tl_if_empty:nF { #1 } { \longdiv_error:nwnn { divisor_invalid } } - \int_compare:nNnT \l__longdiv_temp_int = \c_zero { + \int_compare:nNnT \l__longdiv_temp_int = \c_zero_int { \longdiv_error:nwnn { divisor_zero } } } @@ -225,22 +357,6 @@ \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. } -\msg_new:nnn { longdivision } { no_tikz } { You ~ requested ~ "style~=~tikz" ~ but ~ tikz ~ has ~ not ~ been ~ loaded. ~ Falling ~ back ~ to ~ "style~=~standard". } - - %% %% Division %% @@ -253,7 +369,7 @@ % 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: % + \longdiv_record_point: % \bool_set_false:N \l__longdiv_seen_digit_bool \bool_set_true:N \l__longdiv_added_point_bool } @@ -265,8 +381,8 @@ \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: + \longdiv_if_token_is_decimal_separator:NTF #3 { + \longdiv_record_point: \bool_set_true:N \l__longdiv_seen_digit_bool % Prevent this decimal point from being removed later \bool_set_false:N \l__longdiv_added_point_bool \longdiv_get_new_digit:nnn { #1 } { #2 } { #4 } @@ -276,15 +392,13 @@ } % 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 - +\cs_new:Nn \longdiv_record_point: { + \bool_if:NF \l__longdiv_seen_digit_bool { + \tl_put_right:Nn \l__longdiv_quotient_tl { 0 } % Add a leading zero } - \int_set_eq:NN \l__longdiv_point_digit_int \l__longdiv_position_int % Record the position of the point + \int_set_eq:NN \l__longdiv_point_digit_dividend_int { \l__longdiv_position_int } % Record the position of the point + \bool_set_true:N \l__longdiv_seen_point_bool + \int_set:Nn \l__longdiv_point_digit_quotient_int { \tl_count:N \l__longdiv_quotient_tl } } % Divide when we still have more digits. @@ -297,17 +411,17 @@ }{ \int_set:Nn \l__longdiv_quotient_int { \int_div_truncate:nn { #1 } { #2 } } \bool_if:nTF { - \int_compare_p:nNn \l__longdiv_quotient_int = \c_zero % If the quotient was zero, we might not have to print it + \int_compare_p:nNn \l__longdiv_quotient_int = \c_zero_int % 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 }{ \int_incr:N \l__longdiv_digits_requested_int % Get an extra digit, this one doesn't count. }{ % 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 } + \tl_put_right:Nf \l__longdiv_quotient_tl { \int_use:N \l__longdiv_quotient_int } } \int_incr:N \l__longdiv_position_int - \longdiv_divide_record:nn{ #1 }{ #2 } + \longdiv_divide_record:nn { #1 }{ #2 } \longdiv_get_new_digit:xnn { \longdiv_remainder:nn { #1 } { #2 } } { #2 } } } @@ -326,13 +440,14 @@ % For some reason we need to shift the typeset work over by half a digit if we quit early due to "stage" option % so we need to set a flag so that the work typesetter can know to do this. \bool_set_true:N \l__longdiv_stopped_early_stage_bool - % \int_set:Nn \l_tmpa_int { \use:c { longdiv_linkedlist ~ \int_eval:n { \l__longdiv_linkedlist_length_int - 1 } } } - \longdiv_linkedlist_add:n { \phantom { #3 0 } } - \exp_args:Nx \longdiv_typeset:nnn { \longdiv_delete_last:n { #1 } } { #2 } + \tl_put_right:Nn \l__longdiv_quotient_tl { {\longdiv_hphantom:n { #3 0 }} } + \tl_set:Nf \l__longdiv_remainer { \tl_range:nnn { #1 } { 1 } { -2 } } + \longdiv_typeset: } -% Deletes the last digit of number. -\cs_new:Nn \longdiv_delete_last:n { \tl_reverse:f { \tl_tail:f { \tl_reverse:f { #1 } } } } +% \relax to protect also against f expansion +\cs_new:Nn \longdiv_hphantom:n { \relax \longdiv_hphantom_aux: { #1 } } +\cs_new_protected:Nn \longdiv_hphantom_aux: { \hphantom } % Divide when we are out of digits. % #1 -- remainder from last time (we will add a zero to the end) @@ -343,28 +458,33 @@ % 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 } + \tl_set:Nn \l__longdiv_remainder_tl { #1 } + \longdiv_typeset: }{ - \bool_if:nTF { + \bool_if:nTF { % Check if we should stop early \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_p:nNn \l__longdiv_position_int = \l__longdiv_digits_requested_int + ||\int_compare_p:nNn \l__longdiv_position_int = \l__longdiv_digits_requested_int % This is from the "stage" option }{ \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 } + \tl_set:Nn \l__longdiv_remainder_tl { #1 } + \longdiv_typeset: }{ % 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 + % \l__longdiv_repeat_digit_int counts digits after the decimal point, so in 1/9 it will be 0. + % See also the comment above \longdiv_insert_separators:Nn \cs_set:cpx { longdiv_remainders ~ \int_eval:n { #1 } }{ % \int_eval:n to remove leading zero - \int_set:Nn \l__longdiv_repeat_digit_int { \int_use:N \l__longdiv_linkedlist_length_int } - \exp_not:N \longdiv_linkedlist_indicate_repeating_decimal:n { \int_use:N \l__longdiv_linkedlist_length_int } + \exp_not:N \int_set:Nn \exp_not:N \l__longdiv_repeat_digit_int { + \tl_count:N \l__longdiv_quotient_tl - \int_use:N \l__longdiv_point_digit_quotient_int + } } % Now we have to use #1 0 everywhere \int_set:Nn \l__longdiv_quotient_int { \int_div_truncate:nn { #1 0 } { #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 + \tl_put_right:Nf \l__longdiv_quotient_tl { \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 \int_incr:N \l__longdiv_position_int \int_incr:N \l__longdiv_extra_digits_int \longdiv_divide_record:nn { #1 0 } { #2 } @@ -380,7 +500,7 @@ % 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 + \int_compare:nNnTF \l__longdiv_quotient_int = \c_zero_int { #1 } { \int_eval:n { #1 - \l__longdiv_quotient_int * #2 } } } @@ -393,7 +513,7 @@ \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 + \int_compare:nNnF \l__longdiv_quotient_int = \c_zero_int { % 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 } } @@ -402,7 +522,8 @@ } }{ \int_compare:nNnT \l__longdiv_display_divisions_int = \c__longdiv_max_display_divisions_int { - \int_compare:nNnF \l__longdiv_quotient_int = \c_zero { + % If we hit max_display_divisions, we need to use typeset_work_last and emit a stopped-early warning. Otherwise this is the same as the display_divisions < max_display_divisions case. + \int_compare:nNnF \l__longdiv_quotient_int = \c_zero_int { \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 } } @@ -419,212 +540,272 @@ %% Typesetting %% +% This is the bulk of the code, division is quite easy but arranging stuff on the page is much harder. + +\cs_new_protected:Nn \longdiv_return_to_original_mode:n { \bool_if:NF \l__longdiv_mathmode_bool \hbox { #1 } } %% Indicate repeating decimals -% These are all different implementations of \longdiv_linkedlist_indicate_repeating_decimal:n +% These are all different implementations of \longdiv_indicate_repeating_decimal:n % They take one input which is the index of the start of the repeating decimal in the linked list -% Chosen using "repeating decimal style", default is "dots all" +% Chosen using "repeating decimal style", default is "overline" % possible values: "overline", "dots", "dots all", "parentheses" -% Put an \overline over the repeated digits. \overline only works in math mode, so we have to use \ensuremath. Then we put an \hbox -% to take ourselves -\cs_new:Nn \longdiv_linkedlist_indicate_repeating_decimal_overline:n { - \cs_set:cpx { longdiv_linkedlist ~ #1 }{ - \ensuremath{ \overline { \bool_if:NF \l__longdiv_mathmode_bool \hbox { \exp_not:f { \use:c { longdiv_linkedlist ~ #1 } } } } } - } +% Put an \overline over the repeated digits. \overline only works in math mode, so we have to use \ensuremath. +% \longdiv_return_to_original_mode:n restores text mode by wrapping in an hbox if necessary. +% We stored the top level mode at the beginning of \longdiv_typeset: +\cs_new:Nn \longdiv_indicate_repeating_decimal_overline:n { + \longdiv_ensuremath:n { \overline { \longdiv_return_to_original_mode:n { + #1 + } } } } -\cs_new:cn { longdiv_linkedlist_indicate_repeating_decimal_dots~all:n } { - \cs_set:cpx { longdiv_linkedlist ~ #1 }{ - \exp_not:n { - \cs_set:Npn \longdiv_linkedlist_element:n ##1 { \dot ##1 } - } - \ensuremath { \noexpand \dot \exp_not:f { \use:c { longdiv_linkedlist ~ #1 } } } +\cs_new_protected:Nn \longdiv_dot:n { + % In the dotsall case, we use this on every digit in range, but we don't want to put dots over the + % punctuation so we test for it. + \longdiv_if_digit:nTF { #1 } { + \longdiv_ensuremath:n { \dot { \longdiv_return_to_original_mode:n { #1 } } } + }{ + #1 } } -\cs_new:Nn \longdiv_linkedlist_indicate_repeating_decimal_dots:n { - \cs_set:cpx { longdiv_linkedlist ~ \int_eval:n { \l__longdiv_linkedlist_length_int - 1 } }{ - \noexpand\dot \use:c { longdiv_linkedlist ~ \int_eval:n { \l__longdiv_linkedlist_length_int - 1 } } - } - \cs_set:cpx { longdiv_linkedlist ~ #1 }{ - \ensuremath { \noexpand \dot \exp_not:f { \use:c { longdiv_linkedlist ~ #1 } } } - } +% #1 -- put a dot over every digit in #1. This needs to be expandable like all the indicate_repeating_decimal variants. +\cs_new:cn { longdiv_indicate_repeating_decimal_dots~all:n } { + \tl_map_function:nN { #1 } \longdiv_dot:n % \tl_map_function is expandable whereas \tl_map_inline is not. } -\bool_new:N \l__longdiv_repeating_decimal_parentheses_bool -\cs_new:Nn \longdiv_linkedlist_indicate_repeating_decimal_parentheses:n { - \cs_set:cpx { longdiv_linkedlist ~ #1 }{ - ( \exp_not:f { \use:c { longdiv_linkedlist ~ #1 } } ) - } - % Don't insert extra space for parenthesis in german typesetting because the quotient isn't directly above dividend and work. - \cs_if_eq:NNF \longdiv_typeset_main: \longdiv_typeset_main_german:{ - \bool_set_true:N \l__longdiv_repeating_decimal_parentheses_bool - \cs_set:Nn \longdiv_typeset_extra_zeroes: { - \bool_if:NT \l__longdiv_added_point_bool { . } - \prg_replicate:nn { #1 - \l__longdiv_linkedlist_length_int + \l__longdiv_extra_digits_int } { 0 } \hphantom ( - \prg_replicate:nn { \l__longdiv_position_int - #1 } { 0 } \hphantom{ ) } - } - } +% Put a dot over the first and last entry of the token list leaving the rest alone +\cs_new:Nn \longdiv_indicate_repeating_decimal_dots:n { + \longdiv_dot:n { \tl_head:n { #1 } } + % tl_range wraps it's output in an \exp_not:n which we cancel out with this \expanded + % (I guess in expl3 this is \use:e) + \expanded { \tl_range:nnn { #1 } { 2 } { -2 } } + \longdiv_dot:n { \tl_item:nn { #1 } { -1 } } } -% Do nothing, don't indicate repeating digits at all. -\cs_new:Nn \longdiv_linkedlist_indicate_repeating_decimal_none:n { +\bool_new:N \l__longdiv_repeating_decimal_parentheses_bool + +\cs_new:Nn \longdiv_indicate_repeating_decimal_parentheses:n { + (#1) +} +% In the parentheses case, the parentheses take up space so we record that here +\cs_new:Nn \longdiv_indicate_repeating_decimal_parentheses_skip_begin: { + { \longdiv_hphantom:n { ( } } } -\cs_new_eq:NN \longdiv_linkedlist_indicate_repeating_decimal:n \longdiv_linkedlist_indicate_repeating_decimal_overline:n +\cs_new:Nn \longdiv_indicate_repeating_decimal_parentheses_skip_end: { + { \longdiv_hphantom:n { ) } } +} -% \l__longdiv_linkedlist_tl -- quotient -% #1 -- remainder -% #2 -- divisor -% #3 -- dividend -\cs_new:Nn \longdiv_typeset:nnn { - \mode_if_math:TF { \bool_set_true:N \l__longdiv_mathmode_bool } { \bool_set_false:N \l__longdiv_mathmode_bool } - \cs_set:Npn \longdiv_typeset_dividend: { - \longdiv_typeset_number:n { - #3 - \bool_if:NT \l__longdiv_seen_digit_bool { % we don't want to add a trailing decimal point to the dividend if it divided evenly - \longdiv_typeset_extra_zeroes: - } - } +% Do nothing, don't indicate repeating digits at all. +\cs_new:Nn \longdiv_indicate_repeating_decimal_none:n { #1 } + +% Default is overline +\cs_new_eq:NN \longdiv_indicate_repeating_decimal:n \longdiv_indicate_repeating_decimal_overline:n + +% The three markers are inserted by \longdiv_insert_separators:Nn into quotient, dividend, and work. +% We give them various definitions in the three contexts depending on how we do the formatting. +% typeset_work is typically happening inside of a tabular where each row is in a separate local context, +% so we need to make definitions global for that case. For sanitation purposes, we get rid of the defintions +% as soon as we are done with them. +\cs_new:Nn \longdiv_undefine_markers: { + \cs_undefine:N \longdiv_decimal_separator_marker: + \cs_undefine:N \longdiv_digit_separator_marker: + \cs_undefine:N \longdiv_repeat_marker: +} + +\cs_new:Nn \longdiv_typeset_work: { + \bool_if:NTF \l__longdiv_separators_in_work_bool { % This is the "separators in work" option. + \cs_gset:Nn \longdiv_decimal_separator_marker: { \longdiv_decimal_separator: } % If true print the separators + \cs_gset:Nn \longdiv_digit_separator_marker: { \longdiv_digit_separator: } + }{ + \cs_gset:Nn \longdiv_decimal_separator_marker: {{ \longdiv_hphantom:n { \longdiv_decimal_separator: } }} % Else use \phantom + \cs_gset:Nn \longdiv_digit_separator_marker: {{ \longdiv_hphantom:n { \longdiv_digit_separator: } }} } - \cs_set:Npn \longdiv_typeset_work: { \longdiv_typeset_work:n { #1 } } - \cs_set:Npn \longdiv_typeset_divisor: { \longdiv_typeset_number:n { #2 } } - \cs_set:Npn \longdiv_typeset_remainder: { \longdiv_typeset_number:n { #1 } } % This isn't used in current typesetting code, just could be nice to have - \bool_set:Nn \l_longdiv_repeating_decimal_bool { \int_compare_p:nNn \l__longdiv_repeat_digit_int > 0 } % This isn't used in current typesetting code, just could be nice to have - \let\longdivdividend\longdiv_typeset_dividend: - \let\longdivdivisor\longdiv_typeset_divisor: - \let\longdivquotient\longdiv_typeset_quotient: - \let\longdivwork\longdiv_typeset_work: - \bool_if:NF \l__longdiv_seen_digit_bool { \longdiv_linkedlist_remove_tail: } % If we haven't seen any new digits since adding a terminal decimal point, delete it. - \longdiv_typeset_main: + \cs_gset:Nn \longdiv_repeat_marker: { \longdiv_indicate_repeating_decimal_skip_begin: } % Leave a space (if we are in parentheses case) if we see the repeat_marker. + \longdiv_typeset_work:n { \tl_use:N \l__longdiv_remainder_tl } + \longdiv_undefine_markers: } - -\cs_new:Nn \longdiv_typeset_extra_zeroes: { - \bool_if:NT \l__longdiv_added_point_bool { . } - \prg_replicate:nn { \l__longdiv_extra_digits_int } { 0 } +\cs_new_protected:Nn \longdiv_ensuremath:n { \ensuremath{#1} } +% Choose mathmode or not mathmode as appropriate. \l__longdiv_mathmode_bool is set in \longdiv_typeset: +\cs_new_protected:Nn \longdiv_typeset_number:n { + \bool_if:NTF \l__longdiv_mathmode_bool { \longdiv_ensuremath:n { #1 } } { \hbox { #1 } } } -\cs_new:Nn \longdiv_typeset_main_default: { - \bool_if:NTF \l__longdiv_is_tikz_loaded_bool { - \longdiv_typeset_main_tikz: - } { - \longdiv_typeset_main_standard: - } +\cs_new:Nn \longdiv_typeset_divisor: { + \longdiv_typeset_number:n { \tl_use:N \l__longdiv_divisor_tl } } -\cs_new_eq:NN \longdiv_typeset_main: \longdiv_typeset_main_default: - -\longdiv_define_style:nn { standard } { - \hskip4pt - \rule{0pt}{22pt} \longdiv_typeset_divisor: \, \begin{tabular}[b]{@{}r@{}} - \longdiv_typeset_quotient:\, - \\\hline - - \smash{\big)}\begin{tabular}[t]{@{}l@{}} - \longdiv_typeset_dividend: \\ - \longdiv_typeset_work:\\[3pt] - \end{tabular}\, - \end{tabular} - \hskip5.3pt +\cs_new:Nn \longdiv_typeset_dividend: { + \longdiv_typeset_number:n { \tl_use:N \l__longdiv_dividend_tl } } -\bool_new:N \l__longdiv_is_tikz_loaded_bool -\AtBeginDocument{ \@ifpackageloaded { tikz }{ \bool_gset_true:N \l__longdiv_is_tikz_loaded_bool } { } } - -\longdiv_define_style:nn { german } { - \begin{tabular}[t]{@{}l@{}} - \longdiv_typeset_dividend: \hskip1pt : \hskip1pt \longdiv_typeset_divisor: \hskip4pt = \hskip4pt \longdiv_typeset_quotient: \\ - \longdiv_typeset_work: - \end{tabular} +\cs_set:Npn \longdiv_typeset_quotient: { + \longdiv_typeset_number:n { \tl_use:N \l__longdiv_quotient_tl } } - -\newlength{\longdiv@dividendlength} -\newlength{\longdiv@dividendheight} -\newlength{\longdiv@divisorheight} -\newlength{\longdiv@maxheight} - -\let\longdiv@ifl@aded\@ifl@aded -\let\longdiv@pkgextension\@pkgextension -\def\longdiv@ifpackageloaded{\@ifl@aded\@pkgextension} - -\longdiv_define_style:nn { tikz }{ - \let\@ifl@aded\longdiv@ifl@aded - \let\@pkgextension \longdiv@pkgextension - \bool_if:NTF \l__longdiv_is_tikz_loaded_bool { - \longdiv@typeset@tikz@rest - } { - \msg_warning:nn { longdivision } { no_tikz } - \longdiv_typeset_main_standard: - } +% This isn't used in current typesetting code, but could be nice to have for integer division for instance +\cs_set:Npn \longdiv_typeset_remainder: { + \longdiv_typeset_number:n { \tl_use:N \l__longdiv_remainder_tl } } +% At this point, the divisor, dividend, quotient, and remainder should all be stored in their appropriate token lists: +% \l__longdiv_divisor_tl +% \l__longdiv_dividend_tl +% \l__longdiv_quotient_tl +% \l__longdiv_remainder_tl +% Of course we also care about all sorts of other state... +\cs_new:Nn \longdiv_typeset: { + % Record whether we are in mathmode or not on the top level so we can make sure to typeset everything consistently + \mode_if_math:TF { \bool_set_true:N \l__longdiv_mathmode_bool } { \bool_set_false:N \l__longdiv_mathmode_bool } -\def\longdiv@typeset@tikz@rest{ - \let\longdiv@typeset@dividend\longdiv_typeset_dividend: - \let\longdiv@typeset@divisor\longdiv_typeset_divisor: - \let\longdiv@typeset@quotient\longdiv_typeset_quotient: - \let\longdiv@typeset@work\longdiv_typeset_work: - \settowidth{\longdiv@dividendlength}{1.\longdiv_typeset_dividend:} - \settoheight{\longdiv@dividendheight}{\longdiv_typeset_dividend:} - \settoheight{\longdiv@maxheight}{\longdiv_typeset_dividend:\longdiv_typeset_divisor:} - \settoheight{\longdiv@divisorheight}{\longdiv_typeset_divisor:} - \l__longdiv_rulethickness_dim = 0.2mm - \longdiv@typeset@main@tikz@helper -} + \longdiv_prepare_divisor: + \longdiv_prepare_dividend: + \longdiv_prepare_quotient: + \longdiv_prepare_remainder: -\ExplSyntaxOff -\def\longdiv@typeset@main@tikz@helper{ - \begin{tikzpicture} [baseline=.5pt] - \draw (1pt,.5*\longdiv@divisorheight) node [left] {\longdiv@typeset@divisor}; - \draw (\longdiv@dividendlength,.5*\longdiv@dividendheight) node [left] {\longdiv@typeset@dividend}; - \draw [line width=0.2mm] (0pt,-.22*\longdiv@dividendheight) arc (-70:60:\longdiv@maxheight*.41 and \longdiv@maxheight*.88) -- ++(\longdiv@dividendlength-2pt,0pt); - \draw (\longdiv@dividendlength,\longdiv@divisorheight+\longdiv@maxheight*.3) node[above left] { - \longdiv@typeset@quotient - }; - \draw (0,0) node[below right] { - \begin{tabular}[t]{@{}l@{}} - \longdiv@typeset@work - \end{tabular} - }; - \end{tikzpicture} -} -\ExplSyntaxOn + % Copy components into "public" commands for custom typeset_main code + \let\longdivwork\longdiv_typeset_work: + \let\longdivdivisor\longdiv_typeset_divisor: + \let\longdivdividend\longdiv_typeset_dividend: + \let\longdivquotient\longdiv_typeset_quotient: + \let\longdivremainder\longdiv_typeset_remainder: + \longdiv_typeset_main: +} -\cs_new:Nn \longdiv_typeset_quotient: { - \int_compare:nNnTF \l__longdiv_linkedlist_length_int = \c_zero - { - \bool_if:NTF \l__longdiv_stopped_early_stage_bool - { } - { \longdiv_typeset_number:n { 0 } } +\cs_new:Nn \longdiv_prepare_divisor: { + \longdiv_insert_separators:Nn \l__longdiv_divisor_tl { \tl_count:N \l__longdiv_divisor_tl } + \cs_gset:Nn \longdiv_digit_separator_marker: { \longdiv_digit_separator: } + \tl_set:Nx \l__longdiv_divisor_tl { \tl_use:N \l__longdiv_divisor_tl } + \longdiv_undefine_markers: +} + +\cs_new:Nn \longdiv_prepare_dividend: { + \tl_set:Nx \l__longdiv_dividend_tl { + \tl_use:N \l__longdiv_dividend_tl + % Pad dividend with extra zeroes as needed + \prg_replicate:nn { \l__longdiv_extra_digits_int } { 0 } + } + % Get rid of decimal separator if present (it gets added back in by insert_separators) + \tl_remove_all:No \l__longdiv_dividend_tl { \longdiv_decimal_separator: } + \longdiv_insert_separators:Nn \l__longdiv_dividend_tl { \l__longdiv_point_digit_dividend_int } + \cs_set:Nn \longdiv_decimal_separator_marker: { \longdiv_decimal_separator: } + \cs_set:Nn \longdiv_digit_separator_marker: { \longdiv_digit_separator: } + \cs_set:Npn \longdiv_repeat_marker: ##1 \s_stop { + \longdiv_indicate_repeating_decimal_dividend:n { ##1 } + } + \tl_set:Nx \l__longdiv_dividend_tl { \tl_use:N \l__longdiv_dividend_tl \s_stop } + \longdiv_undefine_markers: + + % The rest of this function groups punctuation with the digit to its right + % 123,456.789 ==> 123{,4}56{.7}89 + % This is for typesetting the work, we need to measure how far to the right + % to typeset a block that contains the first four digits that should be the width of + % 123{,4}. This format is needed for \longdiv_typeset_setwidth:n to work correctly. + \tl_build_clear:N \l_tmpa_tl + \tl_build_clear:N \l_tmpb_tl + \tl_map_inline:Nn \l__longdiv_dividend_tl { + \tl_build_put_right:Nn \l_tmpb_tl { ##1 } + \longdiv_if_digit:nT { ##1 } { + \tl_build_end:N \l_tmpb_tl + \tl_build_put_right:No \l_tmpa_tl { + \exp_after:wN { \exp:w \exp_end_continue_f:w \tl_use:N \l_tmpb_tl } + } + \tl_build_clear:N \l_tmpb_tl } - { \longdiv_typeset_number:n { \l__longdiv_linkedlist_tl } } + } + % Catch any trailing punctuation + \tl_build_end:N \l_tmpb_tl + \tl_build_put_right:No \l_tmpa_tl { + \exp_after:wN { \exp:w \exp_end_continue_f:w \tl_use:N \l_tmpb_tl } + } + \tl_build_end:N \l_tmpa_tl + % Store retokenized result into \l__longdiv_dividend_tl + \tl_set_eq:NN \l__longdiv_dividend_tl \l_tmpa_tl +} + +\cs_new:Nn \longdiv_prepare_quotient: { + \longdiv_insert_separators:Nn \l__longdiv_quotient_tl { \l__longdiv_point_digit_quotient_int } + \cs_set:Nn \longdiv_decimal_separator_marker: { \longdiv_decimal_separator: } + \cs_set:Nn \longdiv_digit_separator_marker: { \longdiv_digit_separator: } + \cs_set:Npn \longdiv_repeat_marker: ##1 \s_stop { + \longdiv_indicate_repeating_decimal_quotient:n { ##1 } + } + \tl_set:Nx \l__longdiv_quotient_tl { \tl_use:N \l__longdiv_quotient_tl \s_stop } + \longdiv_undefine_markers: +} + +% In the very outside chance that someone defines a format that uses "\longdivremainder", has a 4+ digit remainder, +% AND uses the digit separator option, I have them covered... In the other 99.99% of the time this does nothing. +% Really just here for uniformity. +\cs_new:Nn \longdiv_prepare_remainder: { + \longdiv_insert_separators:Nn \l__longdiv_remainder_tl { \tl_count:N \l__longdiv_remainder_tl } + \cs_gset:Nn \longdiv_digit_separator_marker: { \longdiv_digit_separator: } + \tl_set:Nx \l__longdiv_remainder_tl { \tl_use:N \l__longdiv_remainder_tl } + \longdiv_undefine_markers: +} + +\int_new:N \l__longdiv_temp_length_int + +\cs_generate_variant:Nn \tl_map_inline:nn { fn } +\cs_generate_variant:Nn \tl_put_right:Nn { Nf } +\cs_generate_variant:Nn \tl_build_put_right:Nn { No, Nf } + +% This is the key workhorse for our typesetting engine. +% #1 -- a token list +% #2 -- how many digits of the current number come before the decimal point +% We iterate over the current token list, making a new one with punctuation inserted. +% We use a coordinate system where the digit directly AFTER the decimal point is digit 0, +% the digit directly before the decimal point is digit -1, etc. +% This coordinate system is obviously useful for digit separators which occur based on their position +% relative to the decimal point. +% We set up \l__longdiv_repeat_digit_int so that it is already in these coordinates. +% Any additional decorations that need to be added in the future should use coordiantes relative to the decimal point too. +\cs_new:Nn \longdiv_insert_separators:Nn { + \int_set:Nn \l_tmpa_int { - \int_eval:n { #2 } } + \tl_build_clear:N \l_tmpa_tl + \tl_build_put_right:Nf \l_tmpa_tl { \tl_head:N #1 } + \tl_map_inline:fn { \tl_tail:N #1 } { + \int_incr:N \l_tmpa_int + \int_compare:nNnTF \l_tmpa_int = 0 { + \tl_build_put_right:Nn \l_tmpa_tl { \longdiv_decimal_separator_marker: } + }{ + % Check if \l_tmpa_int is divisible by \l__longdiv_digit_group_length. + \int_compare:nNnT \l_tmpa_int = { \l_tmpa_int / \l__longdiv_digit_group_length * \l__longdiv_digit_group_length } { + \tl_build_put_right:Nn \l_tmpa_tl { \longdiv_digit_separator_marker: } + } + } + \int_compare:nNnT \l_tmpa_int = \l__longdiv_repeat_digit_int { + \tl_build_put_right:Nn \l_tmpa_tl { \longdiv_repeat_marker: } + } + \tl_build_put_right:Nn \l_tmpa_tl { ##1 } + } + \tl_build_get:NN \l_tmpa_tl #1 } -\cs_new:Nn \longdiv_typeset_number:n { - \bool_if:NTF \l__longdiv_mathmode_bool { \ensuremath{#1} } { #1 } -} - % Iterate through the division "work" and typeset it +% Argument is remainder after the final division iteration \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 + % If we quit early, \longdiv_typeset_work_last:nn occurs already in \l__longdiv_work_tl so don't need it again \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 } } } } +\tl_new:N \g__longdiv_work_line_tl + % #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 @@ -632,10 +813,16 @@ % _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 } + \longdiv_typeset_setwidth:n { #1 } \hspace{\g__longdiv_temp_dim} - \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #3 } } - \\\longdiv_rule:nn{#1}{#3} + \tl_gset:Nf \g__longdiv_work_line_tl { #3 } + \longdiv_work_insert_separators:Nn { \g__longdiv_work_line_tl } { #1 } + % We need the definition to be global to make it past the \\. + % Best practice would be to feed in a local variable to insert_separators, but insert_separators + % already uses \l_tmpa_tl and \l_tmb_tl for its own purposes. It would anyways be more error prone to do it that way. + \tl_gset_eq:NN \g__longdiv_work_line_tl \g__longdiv_work_line_tl % Globalize definition from insert_separators + \longdiv_llap_preserve_math_mode:n { \longdiv_typeset_number:n { \g__longdiv_work_line_tl } } + \\\longdiv_rule:N { \g__longdiv_work_line_tl } \peek_meaning:NT \bgroup { \longdiv_typeset_work_rest:nnn } @@ -644,11 +831,17 @@ \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 } } + \tl_gset:Nf \g__longdiv_work_line_tl { #2 } + \longdiv_work_insert_separators:Nn { \g__longdiv_work_line_tl } { #1 } + \tl_gset_eq:NN \g__longdiv_work_line_tl \g__longdiv_work_line_tl + \longdiv_llap_preserve_math_mode:n { \longdiv_typeset_number:n { \g__longdiv_work_line_tl } } \\ \hspace{\g__longdiv_temp_dim} - \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #3 } } - \\\longdiv_rule:nn{#1}{#3} + \tl_gset:Nf \g__longdiv_work_line_tl { #3 } + \longdiv_work_insert_separators:Nn { \g__longdiv_work_line_tl } { #1 } + \tl_gset_eq:NN \g__longdiv_work_line_tl \g__longdiv_work_line_tl + \longdiv_llap_preserve_math_mode:n { \longdiv_typeset_number:n { \g__longdiv_work_line_tl } } + \\\longdiv_rule:N { \g__longdiv_work_line_tl } \peek_meaning:NT \bgroup { \longdiv_typeset_work_rest:nnn } @@ -659,107 +852,148 @@ \cs_new:Nn \longdiv_typeset_work_last:nn { \longdiv_typeset_setwidth:n { #1 } \hspace{\g__longdiv_temp_dim} - \llap { \longdiv_insert_point_ifneeded:nn { #1 } { #2 } } -} - -% #1 -- the start position of the substring -% #2 -- the substring -% #3 -- the position we are checking for -\prg_new_conditional:Nnn \longdiv_if_contains_position:nnn { TF,T,F } { - \bool_if:nTF { - \int_compare_p:nNn { #1 } > #3 - && \int_compare_p:nNn { #1 - \tl_count:n { #2 } } < #3 - }{ - \prg_return_true: - }{ - \prg_return_false: - } + \tl_gset:Nf \g__longdiv_work_line_tl { #2 } + \longdiv_work_insert_separators:Nn { \g__longdiv_work_line_tl } { #1 } + \tl_gset_eq:NN \g__longdiv_work_line_tl \g__longdiv_work_line_tl + \longdiv_llap_preserve_math_mode:n { \longdiv_typeset_number:n { \g__longdiv_work_line_tl } } } -% Set \g__longdiv_temp_dim equal to digitwidth * number of digits -% If we are past the decimal point, add \c__longdiv_pointwidth_dim +% Set \g__longdiv_temp_dim equal to the width of the first #1 digits of dividend (and any punctuation in that range). +% In prepare_dividend we grouped the punctuation together with the following digit so that this works conveniently \cs_new:Nn \longdiv_typeset_setwidth:n { - \dim_gset:Nn \g__longdiv_temp_dim { #1\c__longdiv_digitwidth_dim } + \settowidth \l__longdiv_tempwidth_dim {\tl_range:Nnn \l__longdiv_dividend_tl { 1 } { #1 } \relax } + \dim_gset:Nn \g__longdiv_temp_dim { \l__longdiv_tempwidth_dim } % For some reason we need to shift everything over by half a digit if we quit early due to "stage" option - \bool_if:NT \l__longdiv_stopped_early_stage_bool { \dim_gadd:Nn \g__longdiv_temp_dim { -0.5\c__longdiv_digitwidth_dim } } - \int_compare:nNnT \l__longdiv_point_digit_int < { #1 } { - \dim_gadd:Nn \g__longdiv_temp_dim \c__longdiv_pointwidth_dim - } - \bool_if:NT \l__longdiv_repeating_decimal_parentheses_bool { - \int_compare:nNnT \l__longdiv_repeat_digit_int < { #1 } { - \dim_gadd:Nn \g__longdiv_temp_dim \c__longdiv_parenwidth_dim - } - } + \bool_if:NT \l__longdiv_stopped_early_stage_bool {\dim_gadd:Nn \g__longdiv_temp_dim { -0.5\c__longdiv_digitwidth_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 { - \tl_set:Nn \l_tmpa_tl { #2 } - \bool_if:NT \l__longdiv_repeating_decimal_parentheses_bool { - \longdiv_if_contains_position:nnnT { #1 } { #2 } { \l__longdiv_repeat_digit_int } { - \tl_set:Nx \l_tmpa_tl { - \exp_not:N \longdiv_insert:nff { \hskip \c__longdiv_parenwidth_dim } %) - { \int_eval:n{\l__longdiv_repeat_digit_int - #1 + \tl_count:n { #2 }} } - { \tl_use:N \l_tmpa_tl } - } - } - } - \longdiv_if_contains_position:nnnT { #1 } { #2 } { \l__longdiv_point_digit_int } { - \tl_set:Nx \l_tmpa_tl { \longdiv_insert:nff . {\int_eval:n{\l__longdiv_point_digit_int - #1 + \tl_count:n { #2 }}} { \tl_use:N \l_tmpa_tl } } - } - \longdiv_typeset_number:n { \tl_use:N \l_tmpa_tl } +% #2 is the distance to the right endpoint of the token list #1. +% The distance to decimal point is (point_digit_divident - distance to left endpoint of #1) +\cs_new:Nn \longdiv_work_insert_separators:Nn { + \longdiv_insert_separators:Nn #1 { \l__longdiv_point_digit_dividend_int + \tl_count:N #1 - #2 } } -% Walk #2 digits across #3 and then insert #1 -\cs_new:Nn \longdiv_insert:nnn { - \longdiv_insert_aux:onN { #2 } { #1 } #3 +% I think this is the same as a command from mathtools, but I make my own here. +\cs_new:Nn \longdiv_llap_preserve_math_mode:n { + \if_mode_math: + \llap{$#1$} + \else + \llap{#1} + \fi } -\cs_generate_variant:Nn \longdiv_insert:nnn { nff } -\cs_new:Nn \longdiv_insert_aux:nnN { - \int_compare:nNnTF { #1 } = \c_zero { - #2#3 - }{ - #3 \longdiv_insert_aux:onN { \int_eval:n { #1 - 1 } } { #2 } - } -} -\cs_generate_variant:Nn \longdiv_insert_aux:nnN {onN} - - -% 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 \c__longdiv_parenwidth_dim -\settowidth \c__longdiv_parenwidth_dim { ( } -\newdimen \l__longdiv_tempwidth_dim +\newdimen \l__longdiv_tempwidth_dim \newdimen \l__longdiv_rulethickness_dim \l__longdiv_rulethickness_dim = 0.2mm -\cs_new:Nn \longdiv_rule:nn { +% Make a rule of length the width of token list #1 whose right endpoint is \g__longdiv_temp_dim from the left. +\cs_new:Nn \longdiv_rule:N { \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. - \longdiv_if_contains_position:nnnT { #1 } { #2 } { \l__longdiv_point_digit_int } { - \dim_add:Nn \l__longdiv_tempwidth_dim \c__longdiv_pointwidth_dim - } - % If we use parens to denote the repeating part of the quotient, they take up space too. Test if a paren occurs. - \bool_if:NT \l__longdiv_repeating_decimal_parentheses_bool { - \longdiv_if_contains_position:nnnT { #1 } { #2 } { \l__longdiv_point_digit_int } { - \dim_add:Nn \l__longdiv_tempwidth_dim \c__longdiv_parenwidth_dim - } - } + \settowidth \l__longdiv_tempwidth_dim { \tl_use:N #1 } \box_move_right:nn { \g__longdiv_temp_dim - \l__longdiv_tempwidth_dim } { \vbox:n { \hrule width \l__longdiv_tempwidth_dim height \l__longdiv_rulethickness_dim } } } } + + +%% +%% Typesetting styles +%% + +% The typesetting style is chosen with the "style" key. +% These commands use the five commands which contain the relevant results of the division: +% \longdivdivisor +% \longdivdividend +% \longdivquotient +% \longdivremainder +% \longdivwork + +\longdiv_define_style:nn { default } { + \bool_if:NTF \l__longdiv_is_tikz_loaded_bool { + \longdiv_typeset_main_tikz: + } { + \longdiv_typeset_main_standard: + } +} +\cs_new_eq:NN \longdiv_typeset_main: \longdiv_typeset_main_default: + +% In the normal fonts this looks vaguely okay I guess. +% One nice thing about the standard / german styles is that \tracingall behaves better. +% Tikz really wrecks the \tracingall output (hundreds of thousands of text lines of the tikz parser =( ) +% I believe this is stolen from the ancient plaintex longdiv.tex +\longdiv_define_style:nn { standard } { + \hskip4pt + \rule{0pt}{22pt} \longdivdivisor \, \begin{tabular}[b]{@{}r@{}} + \longdivquotient \, + \\\hline + \smash{\big)}\begin{tabular}[t]{@{}l@{}} + \longdivdividend{\hskip 3pt}\relax \\ + \longdivwork\\[3pt] + \end{tabular}\, + \end{tabular} + \hskip5.3pt +} + +\cs_new:Nn \longdiv_german_division_sign: { : } + +% "German" style because it was first requested by a German. has also been suggested to call it "Latin American" style. +\longdiv_define_style:nn { german } { + \begin{tabular}[t]{@{}l@{}} + \longdivdividend \hskip1pt \longdiv_german_division_sign: \hskip1pt \longdivdivisor \hskip4pt = \hskip4pt \longdivquotient \\ + \longdivwork + \end{tabular} +} + + +% Certainly the pretiest of my three styles. I think I got it from a tex stack exchange post, +% but I apparently didn't credit it when I copied it and I cannot find teh post now. +\longdiv_define_style:nn { tikz }{ + \bool_if:NTF \l__longdiv_is_tikz_loaded_bool { + \longdiv@typeset@main@tikz + } { + \msg_warning:nn { longdivision } { no_tikz } + \longdiv_typeset_main_standard: + } +} + +\bool_new:N \l__longdiv_is_tikz_loaded_bool +\AtBeginDocument{ \@ifpackageloaded { tikz }{ \bool_gset_true:N \l__longdiv_is_tikz_loaded_bool } { } } + + +\ExplSyntaxOff + +\newlength{\longdiv@dividendlength} +\newlength{\longdiv@dividendheight} +\newlength{\longdiv@divisorheight} +\newlength{\longdiv@maxheight} + +% text depth is needed to prevent descending commas from shifting components up weirdly. +\def\longdiv@typeset@main@tikz{ + \settowidth{\longdiv@dividendlength}{1.\longdivdividend} + \settoheight{\longdiv@dividendheight}{\longdivdividend} + \settoheight{\longdiv@maxheight}{\longdivdividend\longdivdivisor} + \settoheight{\longdiv@divisorheight}{\longdivdivisor} + \begin{tikzpicture} [baseline=.5pt, text height=\longdiv@maxheight] + \draw (1pt,.5*\longdiv@divisorheight) + node [left, text depth=0pt] { \longdivdivisor }; + \draw (\longdiv@dividendlength,.5*\longdiv@dividendheight ) + node [left, text depth=0pt] { \longdivdividend }; + \draw [line width=0.2mm] + (0pt,-.22*\longdiv@dividendheight) arc (-70:60:\longdiv@maxheight*.41 and \longdiv@maxheight*.88) + -- ++(\longdiv@dividendlength-2pt, 0pt); + \draw (\longdiv@dividendlength,\longdiv@divisorheight+\longdiv@maxheight*.37) + node[above left, text depth=0pt] { \longdivquotient }; + \draw (1pt,0) node[below right] { + \begin{tabular}[t]{@{}l@{}} + \longdivwork + \end{tabular} + }; + \end{tikzpicture} +} +\ExplSyntaxOn + + + \ExplSyntaxOff |