我想创建一个系数方案来乘以多项式,例如P(x) = x^2 + 2x + 3
如下Q(x) = 4x^2 + 5x + 6
图所示:
我亲手尝试过
\documentclass[12pt,a4paper]{article}
\usepackage{amsmath}
\usepackage{amsfonts}
\usepackage{amssymb}
\usepackage{ polynomial}
\usepackage{polynom}
\usepackage{fourier}
\begin{document}
$P(x) = \polynomial{1,2,3}$
$Q(x) = \polynomial{4,5,6}$
\[\begin{matrix}
{} & {} & 1 & 2 & 3 \\
{} & {} & 4 & 5 & 6 \\
{} & {} & 6 & 12 & 18 \\
{} & 5 & 10 & 15 & {} \\
4 & 8 & 12 & {} & {} \\
4 & 13 & 28 & 32 & 18
\end{matrix}\]
\end{document}
如何自动创建方案(例如,通过使用polynom
包与多项式除法的应用一样)?
答案1
这是一个expl3
版本
\documentclass{article}
\usepackage{xparse,booktabs}
\ExplSyntaxOn
\NewDocumentCommand{\polymult}{mm}
{
\minthao_polymult_compute:nn { #1 } { #2 }
\minthao_polymult_display:
}
\seq_new:N \l_minthao_polymult_first_seq % coefficients of first factor
\seq_new:N \l_minthao_polymult_second_seq % coefficients of second factor
\seq_new:N \l_minthao_polymult_result_seq % coefficients of result
\seq_new:N \l_minthao_polymult_temp_seq % temporary usage
\int_new:N \l_minthao_polymult_first_int % degree of first factor + 1
\int_new:N \l_minthao_polymult_second_int % degree of second factor + 1
\int_new:N \l_minthao_polymult_temp_int % temporary usage
\tl_new:N \l_minthao_polymult_tempa_tl % current coefficient (first factor)
\tl_new:N \l_minthao_polymult_tempb_tl % current coefficient (second factor)
\tl_new:N \l_minthao_polymult_body_tl % table body
\cs_new_protected:Npn \minthao_polymult_compute:nn #1 #2
{
\seq_set_split:Nnn \l_minthao_polymult_first_seq { , } { #1 }
\seq_set_split:Nnn \l_minthao_polymult_second_seq { , } { #2 }
\seq_clear:N \l_minthao_polymult_result_seq
\int_set:Nn \l_minthao_polymult_first_int
{
\seq_count:N \l_minthao_polymult_first_seq
}
\int_set:Nn \l_minthao_polymult_second_int
{
\seq_count:N \l_minthao_polymult_second_seq
}
\int_step_inline:nnnn
{ 2 } % start
{ 1 } % step
{ \l_minthao_polymult_first_int + \l_minthao_polymult_second_int } % end
{
\int_zero:N \l_minthao_polymult_temp_int
% compute the coefficient of degree ##1 - 2
\int_step_inline:nnnn { 0 } { 1 } { ##1 - 2 }
{
% get the coefficients, we'll use 0 if above the degree
\tl_set:Nx \l_minthao_polymult_tempa_tl
{ \seq_item:Nn \l_minthao_polymult_first_seq { ####1 + 1 } }
\tl_set:Nx \l_minthao_polymult_tempb_tl
{ \seq_item:Nn \l_minthao_polymult_second_seq { ##1 - ####1 - 1 } }
% compute the coefficient of the product at the current degree
\int_add:Nn \l_minthao_polymult_temp_int
{
\tl_if_empty:NTF \l_minthao_polymult_tempa_tl { 0 } { \l_minthao_polymult_tempa_tl }
*
\tl_if_empty:NTF \l_minthao_polymult_tempb_tl { 0 } { \l_minthao_polymult_tempb_tl }
}
}
% append the coefficient
\seq_put_right:Nx \l_minthao_polymult_result_seq
{
\int_to_arabic:n { \l_minthao_polymult_temp_int }
}
}
}
\cs_new_protected:Npn \minthao_polymult_display:
{
\tl_clear:N \l_minthao_polymult_body_tl
\__minthao_polymult_build_row:Nnn \l_minthao_polymult_first_seq { 1 } { 0 }
\__minthao_polymult_build_row:Nnn \l_minthao_polymult_second_seq { 1 } { 0 }
\tl_put_right:Nn \l_minthao_polymult_body_tl { \midrule }
\int_step_inline:nnnn { 1 } { 1 } { \l_minthao_polymult_second_int }
{
\__minthao_polymult_build_row:Nnn \l_minthao_polymult_first_seq
{ \seq_item:Nn \l_minthao_polymult_second_seq { ##1 } } { ##1 - 1 }
}
\tl_put_right:Nn \l_minthao_polymult_body_tl { \midrule }
\__minthao_polymult_build_row:Nnn \l_minthao_polymult_result_seq { 1 } { 0 }
\begin{array}{*{\seq_count:N \l_minthao_polymult_result_seq}{c}}
\tl_use:N \l_minthao_polymult_body_tl
\end{array}
}
\cs_new_protected:Npn \__minthao_polymult_build_row:Nnn #1 #2 #3
{% #1 = sequence to use, #2 = multiplier, #3 = right padding
\seq_clear:N \l_minthao_polymult_temp_seq
\seq_map_inline:Nn #1
{
\seq_put_right:Nx \l_minthao_polymult_temp_seq
{ \int_to_arabic:n { ##1 * #2 } }
}
\seq_reverse:N \l_minthao_polymult_temp_seq
% add the left padding
\prg_replicate:nn
{% number of repetitions:
-1*(#3) +
\seq_count:N \l_minthao_polymult_result_seq -
\seq_count:N \l_minthao_polymult_temp_seq
}
{% add blank entries
\seq_put_left:Nn \l_minthao_polymult_temp_seq { }
}
\tl_put_right:Nx \l_minthao_polymult_body_tl
{ \seq_use:Nn \l_minthao_polymult_temp_seq { & } }
\tl_put_right:Nn \l_minthao_polymult_body_tl { \\ }
}
\ExplSyntaxOff
\begin{document}
\[
\polymult{3,2,1}{6,5,4}
\qquad
\polymult{1,1,1,1,1}{-1,1}
\]
\[
\polymult{-2,4,1,-3,10,-10}{-1,8,7,5,2,4}
\]
\end{document}
答案2
您可以尝试宏\mulscheme
。我写它是为了回答您的问题。用法是:
\mulscheme {1 2 3} {4 5 6}
\mulscheme {3 4} {2 3 4 5} etc..
第一个例子的结果和您所展示的相同。
实现如下:
\newcount\totA \newcount\totB \newcount\tmpnum \newcount\spacenum
\def\mulscheme#1#2{%
\tmpnum=0\def\tmp{A}\mulA #1 {} \totA=\tmpnum % reading first parameter
\tmpnum=0\def\tmp{B}\mulA #2 {} \totB=\tmpnum % reading second parameter
\advance\tmpnum by\totA \edef\totT{\the\tmpnum}% sum of totA and totB
\def\linemul{} \tmpnum=0
\loop \ifnum\tmpnum<\totB \advance\tmpnum by1 \mulC \repeat
\edef\linemul{\linemul \mulB#1 {} }%
\edef\muldata{\expandafter\mulF\linemul!\cr}% first line with first parameter
\def\linemul{} \tmpnum=0
\loop \ifnum\tmpnum<\totA \advance\tmpnum by1 \mulC \repeat
\edef\linemul{\linemul \mulB#2 {} }% second line with second parameter
\edef\muldata{\muldata\expandafter\mulF\linemul!\cr\noalign{\mulG\hrule\smallskip}}%
\spacenum=0
\loop \def\linemul{}%
{\tmpnum=0 \loop \ifnum\tmpnum<\spacenum \advance\tmpnum by1 \mulC \repeat}%
{\loop \mulD \advance\totA by-1 \ifnum\totA>0 \repeat}%
{\tmpnum=\totB \loop \ifnum\tmpnum>1 \advance\tmpnum by-1 \mulC \repeat}%
\edef\muldata{\muldata\linemul\cr}%
\advance\spacenum by1 \advance\totB by-1
\ifnum\totB>0 \repeat
\tmpnum=\totT \advance\tmpnum by-1 \def\linemul{}%
\loop \edef\linemul{\linemul\mulE \csname mulT:\the\tmpnum\endcsname}%
\global\expandafter\let\csname mulT:\the\tmpnum\endcsname=\relax
\advance\tmpnum by-1 \ifnum\tmpnum>0 \repeat
\vbox{\halign{&\ \hfil$##$\ \cr\muldata\noalign{\smallskip\hrule\smallskip}\linemul\cr}}%
}
\def\mulA #1 {\ifx^#1^\else
\advance\tmpnum by1
\expandafter\def\csname mul\tmp:\the\tmpnum\endcsname{#1}%
\expandafter\mulA\fi}
\def\mulB #1 {\ifx^#1^\else #1&\expandafter\mulB\fi}
\def\mulC{\xdef\linemul{\space\mulE\linemul}}
\def\mulD{\tmpnum=\csname mulA:\the\totA\endcsname
\multiply\tmpnum by\csname mulB:\the\totB\endcsname
\xdef\linemul{\the\tmpnum \mulE\linemul}
\advance\spacenum by1
\advance\tmpnum by0\csname mulT:\the\spacenum\endcsname
\expandafter\xdef\csname mulT:\the\spacenum\endcsname{\the\tmpnum}%
}
\def\mulE{\ifx\linemul\empty \else&\fi}
\def\mulF#1&!{#1}
\def\mulG{\nointerlineskip\vbox to0pt{\kern-1.1\baselineskip\hbox{$\times$}\vss}\smallskip}
\mulscheme {1 2 3} {4 5 6}
\bigskip\mulscheme {3 4} {2 3 4 5}
仅\newcount
使用 TeX 基元和宏。我尝试在纯 TeX 中使用,但我希望它也可以在 LaTeX 中使用。此宏的主要原理是计算 中的行\linemul
并将其存储到 中\muldata
。完成所有计算后,\halign{...\muldata}
将使用 。
答案3
灵感来自Mathematica Stackexchange 上最近的一个问题,我重新审视了这一点,利用l3fp
可以操作数字元组并将它们乘以标量的事实简化了 egreg 的代码。我还添加了一些键值设置,以明确写入变量的幂(可以选择其名称),避免写入x^0
,并隐藏具有零系数的项。
编辑:请注意,在我的代码中,系数是从最高程度到最低程度给出的,而在 egreg 的代码中则相反。
编辑:我增加了添加颜色等的可能性。
\documentclass{article}
\usepackage{xparse,array,booktabs,multirow,xcolor,colortbl}
\ExplSyntaxOn
\NewDocumentCommand{\polymult}{O{}mm}
{
\group_begin: % to localize the setting of the variable
\keys_set:nn { polymult } {#1}
\polymult_compute:nn {#2} {#3}
\polymult_display:
\group_end:
}
\fp_new:N \l_polymult_P_fp % tuple of coefs of first factor
\fp_new:N \l_polymult_Q_fp % tuple of coefs of second factor
\fp_new:N \l_polymult_PQ_fp % tuple of coefs of result
\int_new:N \l_polymult_degP_int % degree of first factor
\int_new:N \l_polymult_degQ_int % degree of second factor
\int_new:N \l_polymult_ndeg_int % tracks (degQ - current degree)
\int_new:N \l_polymult_row_int % track which row we are on (differs from ndeg if zeros are hidden)
\int_new:N \l_polymult_nrows_int % number of rows of calculation displayed
\int_new:N \l_polymult_term_int % tracks which term we are on
\seq_new:N \l_polymult_rows_seq % coefs of each intermediate row
\tl_new:N \l_polymult_tmp_tl % temporary usage
\tl_new:N \l_polymult_var_tl % variable to use (empty for a bare table)
\bool_new:N \l_polymult_first_term_bool
\bool_new:N \l_polymult_hide_zeros_bool
\bool_new:N \l_polymult_simplify_bool
\bool_new:N \l_polymult_align_signs_bool
\tl_new:N \l_polymult_start_preamble_tl
\tl_new:N \l_polymult_stop_preamble_tl
\tl_new:N \l_polymult_start_P_row_tl
\tl_new:N \l_polymult_stop_P_row_tl
\tl_new:N \l_polymult_start_Q_row_tl
\tl_new:N \l_polymult_stop_Q_row_tl
\tl_new:N \l_polymult_start_first_row_tl
\tl_new:N \l_polymult_stop_first_row_tl
\tl_new:N \l_polymult_start_typical_row_tl
\tl_new:N \l_polymult_stop_typical_row_tl
\tl_new:N \l_polymult_start_last_row_tl
\tl_new:N \l_polymult_stop_last_row_tl
\tl_new:N \l_polymult_start_PQ_row_tl
\tl_new:N \l_polymult_stop_PQ_row_tl
\keys_define:nn { polymult }
{
var .tl_set:N = \l_polymult_var_tl ,
var .initial:n = { } ,
hide-zeros .bool_set:N = \l_polymult_hide_zeros_bool ,
simplify .bool_set:N = \l_polymult_simplify_bool ,
align-signs .bool_set:N = \l_polymult_align_signs_bool ,
start-preamble .tl_set:N = \l_polymult_start_preamble_tl ,
stop-preamble .tl_set:N = \l_polymult_stop_preamble_tl ,
start-P-row .tl_set:N = \l_polymult_start_P_row_tl ,
stop-P-row .tl_set:N = \l_polymult_stop_P_row_tl ,
start-Q-row .tl_set:N = \l_polymult_start_Q_row_tl ,
stop-Q-row .tl_set:N = \l_polymult_stop_Q_row_tl ,
start-first-row .tl_set:N = \l_polymult_start_first_row_tl ,
stop-first-row .tl_set:N = \l_polymult_stop_first_row_tl ,
start-typical-row .tl_set:N = \l_polymult_start_typical_row_tl ,
stop-typical-row .tl_set:N = \l_polymult_stop_typical_row_tl ,
start-last-row .tl_set:N = \l_polymult_start_last_row_tl ,
stop-last-row .tl_set:N = \l_polymult_stop_last_row_tl ,
start-PQ-row .tl_set:N = \l_polymult_start_PQ_row_tl ,
stop-PQ-row .tl_set:N = \l_polymult_stop_PQ_row_tl ,
operations-times .tl_set:N = \l_polymult_times_tl ,
operations-times .initial:n = {\times} ,
operations-plus .tl_set:N = \l_polymult_plus_tl ,
operations-plus .initial:n = {+} ,
operations .meta:n = {
start-preamble = {@{}c@{\,}} ,
start-P-row = {&} ,
start-Q-row = {\l_polymult_times_tl&} ,
start-first-row = {&} ,
start-typical-row = {\l_polymult_plus_tl&} ,
start-last-row = {\l_polymult_plus_tl&} ,
start-PQ-row = {&} ,
},
halfway-operations .meta:n = {
start-preamble = {@{}c@{}} ,
start-P-row = {\multirow{2}{1em}{$\l_polymult_times_tl$}&} ,
start-Q-row = {&} ,
start-first-row = {\multirow{\l_polymult_nrows_int}{1em}{$\l_polymult_plus_tl$}&} ,
start-typical-row = {&} ,
start-last-row = {&} ,
start-PQ-row = {&} ,
}
}
\cs_generate_variant:Nn \clist_map_inline:nn { xn }
\cs_generate_variant:Nn \clist_count:n { e }
\cs_new:Npn \__polymult_tuple_to_clist:n #1
{ \exp_args:Nf \__polymult_tuple_to_clist_aux:n { \fp_to_tl:n {#1} } }
\cs_new:Npn \__polymult_tuple_to_clist_aux:n #1
{
\tl_if_head_eq_charcode:nNTF {#1} ( % )
{ \__polymult_tuple_to_clist_aux:w #1 } {#1}
}
\cs_new:Npn \__polymult_tuple_to_clist_aux:w (#1) {#1}
\cs_new_protected:Npn \polymult_compute:nn #1 #2
{
% Parse the input, evaluate the coefficients only once
\fp_set:Nn \l_polymult_P_fp {#1}
\fp_set:Nn \l_polymult_Q_fp {#2}
\int_set:Nn \l_polymult_degP_int
{ \clist_count:e { \fp_to_tl:N \l_polymult_P_fp } - 1 }
\int_set:Nn \l_polymult_degQ_int
{ \clist_count:e { \fp_to_tl:N \l_polymult_Q_fp } - 1 }
%
% Variables to track the rows, and the total sum (initially zero)
\int_zero:N \l_polymult_row_int
\int_zero:N \l_polymult_ndeg_int
\seq_clear:N \l_polymult_rows_seq
\fp_set:Nn \l_polymult_PQ_fp
{ 0 \prg_replicate:nn { \l_polymult_degP_int + \l_polymult_degQ_int } { ,0 } }
%
% Loop through terms of Q, starting from the highest degree,
% so the rows here are added from right (bottom) to left (top)
\clist_map_inline:xn
{ \__polymult_tuple_to_clist:n { \l_polymult_Q_fp } }
{
\bool_if:nF { \l_polymult_hide_zeros_bool && \fp_compare_p:n { ##1 = 0 } }
{ \int_incr:N \l_polymult_row_int }
\tl_set:Nx \l_polymult_tmp_tl
{ \__polymult_tuple_to_clist:n { ##1 * \l_polymult_P_fp } }
\seq_put_left:Nx \l_polymult_rows_seq { \l_polymult_tmp_tl }
\fp_add:Nn \l_polymult_PQ_fp
{
\prg_replicate:nn { \l_polymult_ndeg_int } { 0, }
\l_polymult_tmp_tl
\prg_replicate:nn { \l_polymult_degQ_int - \l_polymult_ndeg_int } { ,0 }
}
\int_incr:N \l_polymult_ndeg_int
}
\int_set_eq:NN \l_polymult_nrows_int \l_polymult_row_int
}
\cs_new_protected:Npn \polymult_display:
{
% Display P and Q, with a suitable number of empty slots before
\tl_clear:N \l_polymult_body_tl
\__polymult_build_row:nfnn { P }
{ \__polymult_tuple_to_clist:n { \l_polymult_P_fp } }
{ \l_polymult_degQ_int } { 0 }
\__polymult_build_row:nfnn { Q }
{ \__polymult_tuple_to_clist:n { \l_polymult_Q_fp } }
{ \l_polymult_degP_int } { 0 }
%
\tl_put_right:Nn \l_polymult_body_tl { \midrule }
\int_zero:N \l_polymult_row_int
\int_zero:N \l_polymult_ndeg_int
\seq_map_inline:Nn \l_polymult_rows_seq
{
% detecting zero rows
\bool_if:nF
{ \l_polymult_hide_zeros_bool && \fp_compare_p:n { (##1) = 0*(##1) } }
{
\int_incr:N \l_polymult_row_int
\__polymult_build_row:fnnn
{
\int_case:nnF \l_polymult_row_int
{
{ 1 } { first }
{ \l_polymult_nrows_int } { last }
}
{ typical }
}
{##1}
{ \l_polymult_degQ_int - \l_polymult_ndeg_int }
{ \l_polymult_ndeg_int }
}
\int_incr:N \l_polymult_ndeg_int
}
\tl_put_right:Nn \l_polymult_body_tl { \midrule }
\tl_set:Nx \l_polymult_tmp_tl
{ \__polymult_tuple_to_clist:n { \l_polymult_PQ_fp } }
\__polymult_build_row:nfnn { PQ } \l_polymult_tmp_tl { 0 } { 0 }
\exp_args:Nnx \begin{array}
{
\l_polymult_start_preamble_tl
\bool_if:NTF \l_polymult_align_signs_bool
{
* { \int_eval:n { 2 * \clist_count:N \l_polymult_tmp_tl } }
{ @{} r @{} }
}
{ * { \clist_count:N \l_polymult_tmp_tl } { r } }
\l_polymult_stop_preamble_tl
}
\tl_use:N \l_polymult_body_tl
\end{array}
}
\cs_generate_variant:Nn \__polymult_build_row:nnnn { f , nf }
\cs_new_protected:Npn \__polymult_build_row:nnnn #1#2#3#4
{
% #1 = row name , #2 = clist to use, #3 = left padding, #4 = right padding
\tl_put_right:Nx \l_polymult_body_tl
{
\exp_not:v { l_polymult_start_#1_row_tl }
\prg_replicate:nn { \bool_if:NT \l_polymult_align_signs_bool { 2 * } (#3) } { & }
}
\bool_set_true:N \l_polymult_first_term_bool
\int_set:Nn \l_polymult_term_int
{ \l_polymult_degP_int + \l_polymult_degQ_int - (#3) }
\clist_map_inline:nn {#2}
{
\tl_put_right:Nx \l_polymult_body_tl
{
\bool_if:NF \l_polymult_first_term_bool { & }
\bool_if:nTF % BLF here
{ \l_polymult_hide_zeros_bool && \fp_compare_p:n { ##1 = 0 } }
{ & }
{ \__polymult_monomial:nN {##1} \l_polymult_term_int }
}
\bool_set_false:N \l_polymult_first_term_bool
\int_decr:N \l_polymult_term_int
}
\tl_put_right:Nx \l_polymult_body_tl
{
\prg_replicate:nn { \bool_if:NT \l_polymult_align_signs_bool { 2 * } (#4) } { & }
\exp_not:v { l_polymult_stop_#1_row_tl }
\exp_not:N \\
}
}
\cs_new:Npn \__polymult_monomial:nN #1#2
{
\fp_compare:nTF { #1 < 0 }
{ \bool_if:NTF \l_polymult_align_signs_bool { {} - {} } { - } }
{
\bool_if:NF \l_polymult_first_term_bool
{ \tl_if_empty:NF \l_polymult_var_tl { {} + {} } }
}
\bool_if:NT \l_polymult_align_signs_bool { & }
\bool_if:NTF \l_polymult_simplify_bool
{
\int_compare:nNnTF {#2} = 0
{ \fp_abs:n {#1} }
{
\tl_if_empty:NTF \l_polymult_var_tl
{ \fp_abs:n {#1} }
{
\fp_compare:nTF { \fp_abs:n {#1} = 1 } { } { \fp_abs:n {#1} }
\exp_not:N \l_polymult_var_tl
\int_compare:nNnF {#2} = 1 { ^ { \int_use:N #2 } }
}
}
}
{
\fp_abs:n {#1}
\tl_if_empty:NF \l_polymult_var_tl
{ \exp_not:N \l_polymult_var_tl ^ { \int_use:N #2 } }
}
}
\ExplSyntaxOff
\NewDocumentCommand{\minhthienpolymult} {O{}} {%
\polymult[align-signs,
var=x,
simplify,
hide-zeros,
halfway-operations,
operations-times = \color{orange}\times,
operations-plus = \color{orange}+,
start-last-row = \arrayrulecolor{blue}&,
#1]}
\begin{document}
\[
\polymult[halfway-operations, align-signs, var=\mathcal{B}, simplify, hide-zeros]{-1,2,3}{4,5,1,0,6}
\qquad
\polymult[align-signs, var=x, hide-zeros]{1,1,1,1,1}{1,-1}
\]
\[
\polymult{-10,10,-3,1,4,-2}{4,2,5,7,8,-1}
\]
\[
\polymult[operations, align-signs, var=x, simplify, hide-zeros]{-1,0,2}{-4,5,0,6}
\quad
\polymult[align-signs, var=a ,simplify]{1,0,-2,0,-1}{1,-1}
\]
\[
\minhthienpolymult[var=x, hide-zeros=false]{1,1,-1}{2,-7,9}
\]
\end{document}