How can I get the ordinary polynomial long division by using polydiv like this?

6,594

A while back, I had a go at reimplementing polynomial long division because I wanted something similar.

Save this as polydiv.sty

\ProvidesPackage{polydiv}
\RequirePackage{xparse,expl3}
\ExplSyntaxOn

\bool_new:N \l__poly_zeros_bool
\bool_new:N \l__poly_first_bool
\bool_new:N \l__poly_trailing_bool
\bool_new:N \l__poly_ptrailing_bool
\bool_new:N \l__poly_stage_bool
\bool_set_true:N \l__poly_stage_bool
\tl_new:N \l__poly_var_tl
\tl_new:N \l__poly_sep_tl
\tl_new:N \l__poly_longdiv_sep_tl
\tl_new:N \l__poly_oline_tl
\tl_new:N \l__poly_uline_tl
\tl_set:Nn \l__poly_var_tl {x}
\tl_set:Nn \l__poly_sep_tl {}
\tl_set:Nn \l__poly_longdiv_sep_tl {}
\int_new:N \l__poly_deg_int
\int_new:N \l__poly_pad_int
\int_new:N \l__poly_tmpa_int
\int_new:N \l__poly_tmpb_int
\int_new:N \l__poly_trailing_int
\int_new:N \l__poly_stage_int
\int_new:N \l__poly_cstage_int
\int_set:Nn \l__poly_pad_int{3}
\seq_new:N \l__poly_gtmpa_seq

\keys_define:nn { polynomial }
{
  stage .code:n = {
    \bool_set_false:N \l__poly_stage_bool
    \int_set:Nn \l__poly_stage_int {#1}
  },
  zeros .bool_set:N = \l__poly_zeros_bool,
  separator .tl_set:N = \l__poly_sep_tl,
  variable .tl_set:N = \l__poly_var_tl,
  var .tl_set:N = \l__poly_var_tl,
%  trailing .bool_set:N = \l__poly_trailing_bool
}

\cs_new_nopar:Npn \poly_print:N #1 {
  \int_gset:Nn \l__poly_deg_int {\seq_count:N #1}
  \int_gdecr:N \l__poly_deg_int
  \int_gset:Nn \l__poly_tmpa_int {\l__poly_deg_int -
    \l__poly_trailing_int+1}
  \bool_gset_eq:NN \l__poly_ptrailing_bool \l__poly_trailing_bool
  \bool_gset_true:N \l__poly_first_bool
  \int_compare:nT {\l__poly_deg_int < \l__poly_pad_int} {
    \prg_replicate:nn {2*(\l__poly_pad_int -
      \l__poly_deg_int)}{\tl_use:N \l__poly_sep_tl}
  }
  \seq_map_inline:Nn #1 {
    \bool_if:nTF {\int_compare_p:n {##1 == 0} && \l__poly_first_bool}
    {
      \tl_use:N \l__poly_sep_tl
      \tl_use:N \l__poly_sep_tl
    }
    {
      \bool_if:nTF {\int_compare_p:n {##1 != 0} || \l__poly_zeros_bool}
      {
    \int_compare:nTF {##1 < 0} 
    {
          \bool_if:NF \l__poly_first_bool {
        \tl_use:N \l__poly_sep_tl
          }
          - \tl_use:N \l__poly_sep_tl
      \bool_if:nF {\int_compare_p:n {##1 == -1} && \int_compare_p:n {\l__poly_deg_int > 0}}
      {
        \int_eval:n {-##1}
      }
    }
    {
      \bool_if:NF \l__poly_first_bool {\tl_use:N \l__poly_sep_tl+} \tl_use:N \l__poly_sep_tl
      \bool_if:nF {\int_compare_p:n {##1 == 1} && \int_compare_p:n {\l__poly_deg_int > 0}}
      {
        ##1
      }
    }
    \int_compare:nT {\l__poly_deg_int > 0}
    {
      \tl_use:N \l__poly_var_tl
      \int_compare:nT {\l__poly_deg_int > 1} {^{\int_use:N \l__poly_deg_int}}
    }
      }
      {
    \tl_use:N \l__poly_sep_tl
    \tl_use:N \l__poly_sep_tl
      }
      \bool_gset_false:N \l__poly_first_bool
    }
    \int_gdecr:N \l__poly_deg_int
    \bool_if:nT {\l__poly_ptrailing_bool && \int_compare_p:n {\l__poly_deg_int < \l__poly_tmpa_int}} {
      \seq_map_break:
    }
  }
}
\cs_generate_variant:Nn \poly_print:N {c}

\cs_new_nopar:Npn \poly_add:NNN #1#2#3 {
  \seq_clear_new:N #1
  \int_step_inline:nnnn {1} {1} {\int_max:nn {\seq_count:N #2} {\seq_count:N #3}} {
    \seq_put_left:Nx #1 {\int_eval:n {\seq_item:Nn #2 { - ##1} + \seq_item:Nn #3 { - ##1}+0}}
  }
}
\cs_generate_variant:Nn \poly_add:NNN {Ncc,ccc}
\cs_new_nopar:Npn \poly_sub:NNN #1#2#3 {
  \seq_clear_new:N #1
  \int_step_inline:nnnn {1} {1} {\int_max:nn {\seq_count:N #2} {\seq_count:N #3}} {
    \seq_put_left:Nx #1 {\int_eval:n {\seq_item:Nn #2 { - ##1} - \seq_item:Nn #3 { - ##1}+0}}
  }
}
\cs_generate_variant:Nn \poly_sub:NNN {Ncc,ccc}
\cs_new_nopar:Npn \poly_shift:Nn #1#2 {
  \prg_replicate:nn {#2} {
    \seq_put_right:Nn #1 {0}
  }
}
\cs_new_nopar:Npn \poly_mul:NNN #1#2#3 {
  \seq_clear_new:N #1
  \group_begin:
  \seq_clear_new:N \l__poly_tmpa_seq    
  \seq_clear_new:N \l__poly_tmpb_seq    
  \seq_clear_new:N \l__poly_tmpc_seq    
  \int_set:Nn \l__poly_tmpa_int {\seq_count:N #2 - 1}
  \seq_map_inline:Nn #2 {
    \seq_clear:N \l__poly_tmpa_seq
    \seq_map_inline:Nn #3 {
      \seq_put_right:Nx \l__poly_tmpa_seq {\int_eval:n {##1 * ####1}}
    }
    \poly_shift:Nn \l__poly_tmpa_seq {\l__poly_tmpa_int}
    \poly_add:NNN \l__poly_tmpc_seq \l__poly_tmpb_seq \l__poly_tmpa_seq
    \seq_set_eq:NN \l__poly_tmpb_seq \l__poly_tmpc_seq
    \int_decr:N \l__poly_tmpa_int
  }
  \seq_gset_eq:NN \l__poly_gtmpa_seq \l__poly_tmpb_seq
  \group_end:
  \seq_set_eq:NN #1 \l__poly_gtmpa_seq
  \seq_clear:N \l__poly_gtmpa_seq
}
\cs_generate_variant:Nn \poly_mul:NNN {Ncc, ccc}
\cs_new_nopar:Npn \poly_div:NNN #1#2#3 {
  \seq_clear_new:N #1
  \seq_put_left:Nx #1 {\int_eval:n {\seq_item:Nn #2 {1} / \seq_item:Nn #3 {1}}}
  \poly_shift:Nn #1 {\seq_count:N #2 - \seq_count:N #3}
}
\cs_generate_variant:Nn \poly_div:NNN {Ncc, ccc}
\prg_new_conditional:Npnn \poly_is_divisible:NN #1#2 {p,T,F,TF} {
  \int_compare:nTF {\seq_count:N #1 < \seq_count:N #2}
  {
    \prg_return_false:
  }
  {
    \prg_return_true:
  }
}
\cs_new_nopar:Npn \poly_trim:N #1 {
  \bool_do_while:nn {\int_compare_p:n {\seq_item:Nn #1 {1} == 0}} {
    \seq_pop_left:NN #1 \l_tmpa_tl
  }
}
\cs_new_nopar:Npn \poly_longdiv:NN #1#2 {
  \group_begin:
  \seq_clear_new:N \l__poly_quotient_seq
  \seq_clear_new:N \l__poly_remainder_seq
  \seq_clear_new:N \l__poly_factor_seq
  \seq_set_eq:NN \l__poly_remainder_seq #1
  \seq_clear_new:N \l__poly_lines_seq
  \int_zero:N \l__poly_cstage_int
  \bool_do_while:nn {
    \poly_is_divisible_p:NN \l__poly_remainder_seq #2
    &&
    (\l__poly_stage_bool || \int_compare_p:n {\l__poly_stage_int > \l__poly_cstage_int})
  }
  {
    \poly_div:NNN \l__poly_factor_seq \l__poly_remainder_seq #2
    \poly_add:NNN \l__poly_tmpa_seq \l__poly_factor_seq \l__poly_quotient_seq
    \seq_set_eq:NN \l__poly_quotient_seq \l__poly_tmpa_seq
    \poly_mul:NNN \l__poly_tmpa_seq \l__poly_factor_seq #2
    \seq_put_right:NV \l__poly_lines_seq \l__poly_tmpa_seq
    \int_incr:N \l__poly_cstage_int

    \bool_if:nT {\l__poly_stage_bool || \int_compare_p:n
      {\l__poly_stage_int > \l__poly_cstage_int}}
    {
      \poly_sub:NNN \l__poly_tmpb_seq \l__poly_remainder_seq \l__poly_tmpa_seq
      \seq_set_eq:NN \l__poly_remainder_seq \l__poly_tmpb_seq
      \poly_trim:N \l__poly_remainder_seq
      \seq_put_right:NV \l__poly_lines_seq \l__poly_remainder_seq
      \int_incr:N \l__poly_cstage_int
    }
  }
  \int_set:Nn \l__poly_pad_int {\seq_count:N #1 + \seq_count:N
    #2-1}
  \tl_set:Nn \l__poly_sep_tl {&}
  \tl_set:Nn \l__poly_longdiv_sep_tl {\cr}
  \bool_set_true:N \l__poly_zeros_bool
  \int_set:Nn \l__poly_tmpa_int {2*\seq_count:N #1+1}
  \tl_set:Nn \l__poly_oline_tl {\multispan}
  \tl_put_right:Nx \l__poly_oline_tl {{\int_use:N \l__poly_tmpa_int}}
  \tl_put_right:Nn \l__poly_oline_tl {\hrulefill\cr}
  \tl_set:Nn \l__poly_uline_tl {\multispan}
  \tl_put_right:Nx \l__poly_uline_tl {{\int_eval:n {2*\seq_count:N #2 - 1}}}
  \tl_put_right:Nn \l__poly_uline_tl {\hrulefill\cr}
  \int_set:Nn \l__poly_trailing_int {\seq_count:N #2}
  \leavevmode\vbox{\halign {  $##$&&$\>##$ \crcr
    &
    \bool_if:NTF \l__poly_stage_bool
    {
      \bool_set_false:N \l__poly_trailing_bool
    }
    {
      \bool_set_true:N \l__poly_trailing_bool
      \int_set:Nn \l__poly_trailing_int {\l__poly_stage_int/2}
    }
    \poly_print:N \l__poly_quotient_seq
    \tl_use:N \l__poly_longdiv_sep_tl
    \noalign{\vskip-\normalbaselineskip\vskip\jot}
    \prg_replicate:nn {2*\seq_count:N #2} {&}
    \tl_use:N \l__poly_oline_tl
    \int_set:Nn \l__poly_pad_int {0}
    \bool_set_true:N \l__poly_trailing_bool
    \poly_print:N #2
    &
    \smash{\Bigr)}
    &
    \int_set:Nn \l__poly_pad_int {0}
    \bool_set_false:N \l__poly_trailing_bool
    \poly_print:N #1
    \tl_use:N \l__poly_longdiv_sep_tl
    \int_gzero:N \l__poly_tmpb_int
    \seq_map_inline:Nn \l__poly_lines_seq {
      \tl_gset:Nn \l__poly_tmpa_seq {##1}
      \int_gincr:N \l__poly_tmpb_int
      &
      \bool_set_true:N \l__poly_trailing_bool
      \poly_print:N \l__poly_tmpa_seq
      \bool_if:nT {\int_compare_p:n
        {\int_mod:nn{\l__poly_tmpb_int}{2} == 1} &&
        \int_compare_p:n {
          \l__poly_tmpb_int < 2*(\seq_count:N #1 - \seq_count:N #2)
        }
        &&
        \int_compare_p:n {
          \l__poly_tmpb_int != \seq_count:N \l__poly_lines_seq
        }
      } {
        &&\hfill\downarrow\hfill
      }
      \tl_use:N \l__poly_longdiv_sep_tl
      \int_compare:nT {\int_mod:nn{\l__poly_tmpb_int}{2} == 1} {
        \noalign{\vskip-\normalbaselineskip\vskip\jot}
        \prg_replicate:nn {2*\seq_count:N #2 + \l__poly_tmpb_int + 1} {&}
        \tl_use:N \l__poly_uline_tl
      }
    }
    \cr
  }}
  \group_end:
}
\cs_generate_variant:Nn \poly_longdiv:NN {cc}
\NewDocumentCommand \PolyPrint { O{} m } {
  \group_begin:
  \keys_set:nn { polynomial }
  {
    #1
  }
  \poly_print:c {polynomial #2}
  \group_end:
}
\NewDocumentCommand \PolySet { m m } {
  \seq_set_from_clist:cn {polynomial #1} {#2}
}
\NewDocumentCommand \PolyLongDiv {O{} m m } {
  \group_begin:
  \keys_set:nn { polynomial }
  {
    #1
  }
  \poly_longdiv:cc {polynomial #2} {polynomial #3}
  \group_end:
}
\ExplSyntaxOff

Then the following:

\documentclass{article}
%\url{http://tex.stackexchange.com/q/79411/86}
\usepackage{polydiv}

\begin{document}
\PolySet{a}{1,-12,0,-42}
\PolySet{b}{1,-3}
\(\PolyLongDiv{a}{b}\)
\end{document}

produces:

polynomial long division

Share:
6,594

Related videos on Youtube

azhi
Author by

azhi

Updated on August 01, 2022

Comments

  • azhi
    azhi over 1 year

    I want to get the following polynomial long division like this:

    Polynomial Long Division

    But as you know, when I use command \polylongdiv (package polynom), I always get the following:

    polydiv result

    How can I get the result as in the first picture? At present, I have no idea to do so. Here is my tex file:

    \documentclass{article}
    
    \usepackage{polynom}
    
    \begin{document}
    
    $$\polylongdiv{x^3-12x^2-42}{x-3}$$
    
    \end{document}
    
    • Torbjørn T.
      Torbjørn T. about 11 years
      Question is not the same, but the code in How to correct excessive lines at the corner and bad line spaces in polynom.sty? replaces the ")" with a (better placed) vertical line. (For reference: the code comes from latex-community.org/forum/viewtopic.php?p=30051#p30051, and was written by Thorsten Donig.)
    • Werner
      Werner about 11 years
      @azhi: Would you be able to adequately verbalize the difference between the two outputs? For example, do you really want elements like 0x? The horizontal alignment seems to be a major difference. To what extent? Do you want things to still line up with other elements horizontally?
    • Scott H.
      Scott H. about 11 years
      If you're looking for the 0x terms, then see this answer
    • azhi
      azhi about 11 years
      I want the result of the command $\polylongdiv{x^3-12x^2-42}{x-3}$ to be as that of the first picture. Yes, I do really want the elements like $0X$. But what I want most is that the third line of the second picture to be $x^3-3x^2$, other than $-x^3+3x^2$, the fifth line to be $-9x^2+27x$, other than $9x^2-27x$, the seventh line to be $-27x+81$, other than $27x-81$.
    • Nicholas Hamilton
      Nicholas Hamilton almost 11 years
      the way that \polylongdiv is rendering it is strictly correct, aligning terms of the same power.
    • Randy Scott
      Randy Scott about 8 years
      Azhi, I understand your question. You wanted that third line to represent the result of multiplying the current term in the quotient by the divisor. You do NOT want to show the opposite of that product. Did you ever find a way to achieve your goal?
  • rhody
    rhody over 5 years
    Any chance of implementing stage from polynom? Your version uses a better display style.
  • Courtney Gibbons
    Courtney Gibbons over 4 years
    Any chance you can use the package intcalc to calculate coefficients modulo a prime (for examples over the integers mod p) at each step? Signed, a pressed-for-time professor who took a look at the guts of polynom and gave up! :)
  • Andrew Stacey
    Andrew Stacey over 4 years
    @CourtneyGibbons Have you had a look at tex.stackexchange.com/a/444979/86 ? With one caveat regarding division, it might do what you want.
  • Courtney Gibbons
    Courtney Gibbons over 4 years
    @LoopSpace - Awesome! As long as the divisor is monic, life is good! Thanks for the link.
  • Andrew Stacey
    Andrew Stacey over 4 years
    @CourtneyGibbons Non-monic is on my list of "things to do". Usually stuff on that list gets implemented if there's a specific need/request. Without guaranteeing any time-frame, would that be useful?
  • Courtney Gibbons
    Courtney Gibbons over 4 years
    It would be useful -- but don't put it as a high-urgency item unless you need a reason to pick something to do and nothing else is appealing!