在之前关于自动创建函数表的问题中,我从@egreg 那里得到了一个很好的答案这里。我已经简化了这个例子,见下面的代码。
我认为,如果它们按序列排列,我可以用另一个宏来计算 x 值,然后将它们传递给函数表。
\ExplSyntaxOn
\NewExpandableDocumentCommand{\ForA}{ O {1} m m }{
\fp_step_inline:nnnn { #2 } { #1 } { \fp_eval:n { #2+#1*(#3-2) } } { ##1, } \fp_eval:n { #2+#1*(#3-1) } }
\ExplSyntaxOff
\ForA[1]{1}{9}
这给出了一个序列。
\functiontableT{ 1/4,1/3,1/2,\ForA[1]{1}{9},15}{ 1/#1^2 }
不幸的是,按照我尝试的方法,这种方法不起作用。如果能提供提示或帮助,我会非常高兴。
\documentclass{article}
\usepackage{xfp}
\usepackage{xintexpr}
\usepackage{siunitx}
\sisetup{group-separator={\,},output-decimal-marker={,}}
\ExplSyntaxOn
\seq_new:N \l__ts_funcT_row_one_seq
\seq_new:N \l__ts_funcT_row_two_seq
\NewDocumentCommand{\functiontableT}{ m m }
{% #1 = list of values, #2 = function
\group_begin:
\cs_set:Nn \__ts_funcT_function:n { #2 }
\seq_clear:N \l__ts_funcT_row_one_seq
\seq_clear:N \l__ts_funcT_row_two_seq
\clist_map_inline:nn { #1 }
{ \seq_put_right:Nn \l__ts_funcT_row_one_seq
{ $ \xintFrac{\xinttheexpr reduce( ##1 ) \relax } $ }
\seq_put_right:Nx \l__ts_funcT_row_two_seq
{ \num{ \fp_eval:n{round( \__ts_funcT_function:n { \fp_eval:n { ##1 } }, 2 ) } } }
}
\use:x { \exp_not:N \begin{tabular}{ c *{\seq_count:N \l__ts_funcT_row_one_seq}{|c}} }
$ x $ & \seq_use:Nn \l__ts_funcT_row_one_seq { & }
\tabularnewline \hline
$ f(x) $ & \seq_use:Nn \l__ts_funcT_row_two_seq { & }
\end{tabular}
\group_end:
} %
\ExplSyntaxOff
\ExplSyntaxOn
\NewExpandableDocumentCommand{\ForA}{ O {1} m m }{
\fp_step_inline:nnnn { #2 } { #1 } { \fp_eval:n { #2+#1*(#3-2) } } { ##1, } \fp_eval:n { #2+#1*(#3-1) } }
\ExplSyntaxOff
\begin{document}
\ForA[1]{1}{9}
\functiontableT{ 1/4,1/3,1/2,1,2,3,4,5,6,7,8,9}{ 1/#1^2 }
\end{document}
答案1
您可以定义\forA
可扩展的宏,例如像这样:
\def\forA[#1]#2#3{#2\expandafter\forAA\expandafter{\the\numexpr#2+#1}{#3}{#1}}
\def\forAA#1#2#3{\unless\ifnum#1>\numexpr#2,#1%
\forAfi\expandafter\forAA\expandafter{\the\numexpr#1+#3}{#2}{#3}\fi}
\def\forAfi#1\fi{\fi#1}
现在,您可以在中使用它\edef
,例如像这样:
\edef\x{\noexpand\functiontableT{ 1/4,1/3,1/2,\ForA[1]{1}{9},15}}\x { 1/#1^2 }
编辑如果您需要修改宏,该怎么办\functiontableT
(您的评论中提到了此需求)。因此,您可以定义
\let\ftableTori=\functiontableT
\def\functiontableT#1{\edef\tmp{#1}\expandafter\ftableTori\expandafter{\tmp}}
你可以使用
\functiontableT{ 1/4,1/3,1/2,\ForA[1]{1}{9},15}{ 1/#1^2 }
答案2
在@egreg的帮助下,函数表的完整代码(他做了最多的工作)和@wipet的提示如下
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage[ngerman]{babel}
\usepackage{xfp}
\usepackage{xintexpr}
\usepackage{siunitx}
\sisetup{group-separator={\,},output-decimal-marker={,}}
\ExplSyntaxOn
\NewDocumentCommand{\functiontableTS}{O{}mm}% Macro für Wertetabellen in horizontal und vertikal
{% #1 = option list, #2 = list of values, #3 = function
\group_begin:
\keys_set:nn { thomas/functiontable } { #1 } % Setzen der weiter unten definierten KeyValues (KV)
\bool_if:NTF \l__thomas_functiontable_hor_bool % Wenn boolean KV hor true, rufe das Macro \thomas_functiontable_hor:nn auf, sonst das Macro ...vert:nn
{
\thomas_functiontable_hor:nn { #2 } { #3 } % Das hor-Macro wird weiter unten definiert
}
{
\thomas_functiontable_vert:nn { #2 } { #3 } % Das vert-Macro wird ebenfalls weiter unten definiert
}
\group_end:
} % Ende des Hauptmacros
\seq_new:N \__thomas_functiontable_rows_seq % Definition eines Zeilen-Sequenz-Namens, siehe weiter unten: setzt x & f(x)
\seq_new:N \__thomas_functiontable_row_one_seq % Definition eines Zeilen-Sequenz-Namens, siehe weiter unten, setzt in hor Tab die 1. Zeile
\seq_new:N \__thomas_functiontable_row_two_seq % Definition eines Zeilen-Sequenz-Namens, siehe weiter unten, setzt in hor Tab die 2. Zeile
\seq_new:N \l__thomas_functiontable_columns_seq % Definition eines Spalten-Sequenz-Namens, siehe weiter unten: setzt x & f(x)
\keys_define:nn { thomas/functiontable } % Definition der KeyValues
{
hor .bool_set:N = \l__thomas_functiontable_hor_bool, % hor= true bedeutet eine horizontale Tabelle
hor .initial:n = false, % Starteinstellung hor= false, also vertikale Tabelle
hor .default:n = true, % hor und hor = true sind äquivalent
box .bool_set:N = \l__thomas_functiontable_box_bool, % box = true bedeutet mit allen vertikalen und horizontalen Linien in der Tabelle
box .initial:n = false, % Starteinstellung box= false
box .default:n = true, % box und box = true sind äquivalent
bold .bool_set:N = \l__thomas_functiontable_bold_bool, % bold = true bedeutet mit allen vertikalen und horizontalen Linien in der Tabelle
bold .initial:n = false, % Starteinstellung bold= false
bold .default:n = true, % bold und bold = true sind äquivalent
fracx .bool_set:N = \l__thomas_functiontable_fracx_bool,% fracx = true bedeutet die Eingabe von 2/3 mit Darstellung als gekürzter Bruch
fracx .initial:n = true, % Starteinstellung fracx = true
fracx .default:n = true, % fracx und fracx = true sind äquivalent
fracy .bool_set:N = \l__thomas_functiontable_fracy_bool,% fracy = true bedeutet die Eingabe von 2/3 mit Darstellung als gekürzter Bruch
fracy .initial:n = false, % Starteinstellung fracy = false
fracy .default:n = true, % fracy und fracy = true sind äquivalent
round .int_set:N = \l__thomas_functiontable_round_int, % Runden der berechneten Werte
round .initial:n = 2, % Standardmäßig wird auf 2 Dezimalen gerundet
ivar .tl_set:N = \l__thomas_functiontable_ivar_tl, % KV für den Namen der Variablen
ivar .initial:n = x, % Initialisiert mit x
dvar .tl_set:N = \l__thomas_functiontable_dvar_tl, % KV für den Funktionsnamen
dvar .initial:n = f(x), % Initialisiert mit f(x)
align .tl_set:N = \l__thomas_functiontable_align_tl, % Vertikale Ausrichtung der Tabelle gegenüber Fließtext
align .initial:n = t, % Standard auf align=t -> top
fInt .tl_set:N = \l__thomas_functiontable_fInt_tl, % KV, setzt den Wert von table-format in vert-Tabelle in der f(x)-Spalte, wenn siuntx-Def "S" genutzt wird
fInt .initial:n = 2.2,
xInt .tl_set:N = \l__thomas_functiontable_xInt_tl, % KV, setzt den Wert von table-format in vert-Tabelle der x-Spalte, wenn siuntx-Def "S" genutzt wird
xInt .initial:n = 1.1,
str .tl_set:N = \l__thomas_functiontable_str_tl, % KV, setzt den \arraystretch auf angegebenen Wert
str .initial:n = 1.1,
colw .dim_set:N = \l__thomas_functiontable_colw_tl, % KV, setzt die Breite der Spalten (außer der ersten, die ist c) in horizontalen Tabellen
colw .initial:n = 0.6cm,
cols .tl_set:N = \l__thomas_functiontable_make_columns_tl, % KV mit dem eine ganz eigene Tabellen-Präambel eingegeben werden kann, z.B. cols={c|c}
}
\cs_new_protected:Nn \thomas_functiontable_vert:nn % Das vert-Macro, das im Haupt-Macro \functiontable aufgerufen wird
{
\cs_set:Nn \__thomas_functiontable_function:n { #2 } % Funktion wird gesetzt und kann nun mit dem Befehl \_thomas_... verwendet werden
\seq_clear:N \l__thomas_functiontable_rows_seq % Alle Einträge des rows-seq-Macros werden gelöscht
\clist_map_inline:nn { #1 } % \clist_map_inline:nn { comma list } {inline function}
{ % wendet function auf jeden Eintrag der Komma-Liste an und speichert in wieder in einer Kommaliste
\seq_put_right:Nx \l__thomas_functiontable_rows_seq % \seq_put_right:Nx <sequence> {<item>}: hängt <item> rechts an die Sequence an
{
\exp_not:N \__thomas_functiontable_num:n
{ \fp_eval:n { ##1 } } % erster Eintrag wird übernommen
& % Spaltentrenner gesetzt
\exp_not:N \__thomas_functiontable_num:n % Verhindert das Expandieren des Macros \__thomas_functiontable_num:n, formatiert die Einträge
{
\fp_eval:n % berechnet f(x) und rundet den Wert auf den KV \l__thomas_functiontable_round_int
{
round( \__thomas_functiontable_function:n { \fp_eval:n { ##1 } }, \l__thomas_functiontable_round_int )
}
}
}
}
\__thomas_functiontable_make_columns_vert: % Aufruf des Macros \__thomas_functiontable... , das weiter unten erst definiert wird
\renewcommand{\arraystretch}{\l__thomas_functiontable_str_tl}
\use:x % Holt sich aus einer Liste die einzelnen items/tokens \use:x {<expandable tokens>} expandiert das
{ % Argument vollständig und Any hash characters (#) in the argument must be doubled!
\exp_not:N \begin{tabular} % Der Befehl \begin{tabular} soll hier noch nicht ausgeführt werden
[\l__thomas_functiontable_align_tl] % Ausrichtung der Tabelle mit KV-\l__thomas_functiontable_align_tl
{\exp_not:V \l__thomas_functiontable_columns_tl} % Tabellendefinition wird gesetzt aber noch nicht expandiert
}
{ \bool_if:NTF \l__thomas_functiontable_bold_bool {\boldmath}{}
${\l__thomas_functiontable_ivar_tl} $
\bool_if:NTF \l__thomas_functiontable_bold_bool {\unboldmath }{} }
&
{ \bool_if:NTF \l__thomas_functiontable_bold_bool {\boldmath}{}
${\l__thomas_functiontable_dvar_tl} $
\bool_if:NTF \l__thomas_functiontable_bold_bool {\unboldmath}{} }
\\ % Erste Tabellenzeile wird gesetzt mit Zeilenumfracx und \hline
\hline
\seq_use:Nn \l__thomas_functiontable_rows_seq { \\ } % Jetzt wird die Sequenz für die Tabellenzeile aufgerufen und mit { \\ } Zeilenufracx abgeschlossen
\end{tabular}
}
\cs_new_protected:Nn \__thomas_functiontable_make_columns_vert: % Definition des Macros, das oben in \thomas_functiontable_vert:nn aufgerufen wird
{
\tl_if_in:NnTF \l__thomas_functiontable_make_columns_tl { S } % Wenn in der Tabellendefinition ein S ist, dann
{
\cs_set_eq:NN \__thomas_functiontable_num:n \use:n % Setzen von \__thomas_..., mit \use:n holt, bzw verwendet aus der Liste die einzelnen Einträge
}
{
% \cs_set_eq:NN \__thomas_functiontable_num:n \num % Wenn nicht S vorkommt, dann verwende das \num-Macro zur Formatierung der Werte
\cs_set_eq:NN \__thomas_functiontable_num:n \ensuremath \exp_not:N \xintFrac
}
\tl_if_empty:NTF \l__thomas_functiontable_make_columns_tl % Wenn cols=leer, dann gib eine Tabellenpräambel vor
{ % Beginn der vorgegebenen Tabellenpräambel
\cs_set_eq:NN \__thomas_functiontable_num:n \use:n
\tl_set:Nn \l__thomas_functiontable_columns_tl { S[table-format=\l__thomas_functiontable_xInt_tl] | S[table-format=\l__thomas_functiontable_fInt_tl] }
% \tl_set:Nn \l__thomas_functiontable_columns_tl { c | c }
} % Ende der vorgegebenen Tabellenpräambel
{ % Aufteilen der Tabellendefinition am Zeichen "|" in ..seq{1} und seq{2}
\seq_set_split:NnV \l__thomas_functiontable_columns_seq { | } \l__thomas_functiontable_make_columns_tl
\int_compare:nTF { \seq_count:N \l__thomas_functiontable_columns_seq <= 1 } % Wenn ein oder kein Element in der Liste: setzen von ...
{
\tl_set:Nx \l__thomas_functiontable_columns_tl % Tabellenpräambel
{
\l__thomas_functiontable_make_columns_tl | \l__thomas_functiontable_make_columns_tl
}
}
{
\tl_set:Nx \l__thomas_functiontable_columns_tl % Wenn mehr als 1 Element in Liste setzen von Tabellenpräambel ...
{
\seq_item:Nn \l__thomas_functiontable_columns_seq { 1 } % ... und gesplittetes Macro in ...seq { 1 } und ...seq { 2 } setzen
|
\seq_item:Nn \l__thomas_functiontable_columns_seq { 2 }
}
}
}
}
\cs_new_protected:Nn \thomas_functiontable_hor:nn % Macro für die horizontale Tabelle definieren
{
\cs_set:Nn \__thomas_functiontable_function:n { #2 } % Funktion definieren
\seq_clear:N \l__thomas_functiontable_row_one_seq % Erste Zeilensequenz leeren
\seq_clear:N \l__thomas_functiontable_row_two_seq % Zweite Zeilensequenz leeren
\clist_map_inline:nn { #1 } % wendet die inline-function -> zweite geschw. Klammer
{ % auf jeden Eintrag (#1) der Komma-Liste an und speichert in wieder in einer Kommaliste
\seq_put_right:Nn \l__thomas_functiontable_row_one_seq {
\bool_if:NTF \l__thomas_functiontable_fracx_bool
{ $ \xintFrac{\xinttheexpr reduce( ##1 ) \relax } $ }
{ \num{##1} } % In die erste Zeile kommen die Werte der Liste
}
\seq_put_right:Nx \l__thomas_functiontable_row_two_seq % In die zweite Zeile kommen die berechneten Funktionswerte
{
\bool_if:NTF \l__thomas_functiontable_fracy_bool
{ $ \xintFrac{\xinttheexpr reduce( \fp_eval:n { ( \__thomas_functiontable_function:n { \fp_eval:n { ##1 } } ) } ) \relax } $ }
{ \num
{
\fp_eval:n
{
round( \__thomas_functiontable_function:n { \fp_eval:n { ##1 } }, \l__thomas_functiontable_round_int )
}
}
}
}
}
\__thomas_functiontable_make_columns_hor: % Das ...make_columns_hor-Macro wird ausgeführt
\renewcommand{\arraystretch}{\l__thomas_functiontable_str_tl}
\use:x %Fully expands the <expandable tokens> and inserts the result into the input stream at the current location. Jedes (#) im Argument must be doubled.
{
\exp_not:N \begin{tabular} % \begin{tabular} noch nicht expandieren
[\l__thomas_functiontable_align_tl] % align=t/b/c setzen gegenüber Text in der Umgebung
{\exp_not:V \l__thomas_functiontable_columns_tl} % Tabellenpräambel setzen, aber noch nicht expandieren
\bool_if:NTF \l__thomas_functiontable_box_bool { \exp_not:N\hline } { } % Wenn box=true dann \hline setzen
}
{ \bool_if:NTF \l__thomas_functiontable_bold_bool {\boldmath}{}
${\l__thomas_functiontable_ivar_tl} $
\bool_if:NTF \l__thomas_functiontable_bold_bool {\unboldmath}{} }
& \seq_use:Nn \l__thomas_functiontable_row_one_seq { & } % erste Zeile setzen
\tabularnewline
\hline
{ \bool_if:NTF \l__thomas_functiontable_bold_bool {\boldmath}{}
${\l__thomas_functiontable_dvar_tl} $
\bool_if:NTF \l__thomas_functiontable_bold_bool {\unboldmath}{} }
& \seq_use:Nn \l__thomas_functiontable_row_two_seq { & } % zweite Zeile setzen
\bool_if:NTF \l__thomas_functiontable_box_bool { \tabularnewline\hline } { } % Wenn box=true dann Zeilenumfracx und \hline setzen
\end{tabular}
}
\cs_new_protected:Nn \__thomas_functiontable_make_columns_hor: % ...make_columns_hor-Macro definieren
{
\tl_if_empty:NTF \l__thomas_functiontable_make_columns_tl % Tabellenpräambel definieren, falls cols=leer
{
\tl_set:Nx \l__thomas_functiontable_columns_tl
{
\bool_if:NTF \l__thomas_functiontable_box_bool { | } { } % Wenn box=true dann am Anfang "|" setzen
c % Erste Spalte ist eine c-Spalte, dann *{...}, also Spaltendef..
*{\seq_count:N \l__thomas_functiontable_row_one_seq}{|>{\exp_not:V\centering}p{\l__thomas_functiontable_colw_tl } }% ..so oft wiederholen wie Anz. Elemente
% *{\seq_count:N \l__thomas_functiontable_row_one_seq}{|c}%
\bool_if:NTF \l__thomas_functiontable_box_bool { | } { } % Wenn box=true dann am Ende "|" setzen
}
}
{
\seq_set_split:NnV \l__thomas_functiontable_columns_seq { | } \l__thomas_functiontable_make_columns_tl % Macro an | splitten und in ...columns_seq{1} bzw {2}
\int_compare:nTF { \seq_count:N \l__thomas_functiontable_columns_seq <= 1 } % Wenn ein oder kein Element in der Liste: setzen von ...
{
\tl_set:Nx \l__thomas_functiontable_columns_tl % Tabellenpräambel
{
\l__thomas_functiontable_make_columns_tl
*{\seq_count:N \l__thomas_functiontable_row_one_seq}{|\l__thomas_functiontable_make_columns_tl}
}
}
{ % Wenn mehr als ein Element in der Liste: setzen von ...
\tl_set:Nx \l__thomas_functiontable_columns_tl % Tabellenpräambel
{
\bool_if:NTF \l__thomas_functiontable_box_bool { | } { } % Wenn box=true dann am Anfang "|" setzen
\seq_item:Nn \l__thomas_functiontable_columns_seq { 1 }
*{\seq_count:N \l__thomas_functiontable_row_one_seq}
{
|\seq_item:Nn \l__thomas_functiontable_columns_seq { 2 }
}
\bool_if:NTF \l__thomas_functiontable_box_bool { | } { } % Wenn box=true dann am Ende "|" setzen
}
}
}
}
\ExplSyntaxOff
\def\forA[#1]#2#3{#2\expandafter\forAA\expandafter{\thexintfloatexpr #2+#1\relax}{#3}{#1}}
\def\forAA#1#2#3{\xintifboolexpr{#1>#2}{}{,#1
\forAfi\expandafter\forAA\expandafter{\thexintfloatexpr #1+#3\relax}{#2}{#3}}}
\def\forAfi#1{#1}
\ExplSyntaxOn
\NewDocumentCommand{\functiontable}{O{}mm}{
\group_begin:
\keys_set:nn { thomas/functiontable } { #1 }
\edef\tmp{#2}\expandafter\functiontableTS\expandafter{\tmp}{#3}
\group_end:
} %
\ExplSyntaxOff
\parindent0pt
\begin{document}
\functiontable[hor,cols=c|c]{1, 2, 3, 4,\xinttheexpr 5! \relax}{ #1^2+3 }
\functiontable[str=0.9]{1, 2, 3.5, 4}{ #1^2+3 }
\functiontable[hor,colw=0.8cm,fracx=true,fracy,str=1.3,box,round=8]{1, 2,7/2, 4}{ #1^2+3 }
\functiontable[xInt=2.4,fInt=3.3]{1, 2, 3.5, 4}{ #1^2+3 }
\functiontable[cols={ c | c }]{1, 2, 7/2, 4}{ #1^2+3 }
\functiontable[hor]{1, 2, 3.5, 4}{ ln(\xinttheexpr #1! \relax) }
\functiontable[hor]{ 1/4,1/3,1/2,\forA[1.5]{2.3}{8},15}{ 1/#1^2 }
\functiontable[round=4,fInt=1.4]{ 1/2,1,2,3,4,5,\forA[0.5]{6.5}{12} }{ 1/#1^2 }
\end{document}