1

In a previous question about the automatic creation of a functiontable I got a very good answer from @egreg here. I have reduced this example, see code below.

I thought I could calculate the x-values with another macro if they were in a sequence and then passed them to the functiontable.

\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}

This gives a sequence.

enter image description here

\functiontableT{ 1/4,1/3,1/2,\ForA[1]{1}{9},15}{ 1/#1^2 }

Unfortunately that does not work in combination the way I tried. About hints or help, I would be very happy.

enter image description here

\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} 
2
  • 1
    \fp_step_inline:nnnn is not expandable.
    – egreg
    Nov 18, 2017 at 23:56
  • @egreg thanks for your hint. Do you know if there is an expandable command I could use?
    – user139826
    Nov 19, 2017 at 6:09

2 Answers 2

3

You can define your \forA macro expandable, for example like this:

\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}

Now, you can use it in \edef, for example, like this:

\edef\x{\noexpand\functiontableT{ 1/4,1/3,1/2,\ForA[1]{1}{9},15}}\x { 1/#1^2 }

EDIT what can you do if you need to modify your \functiontableT macro (this need is mentioned in your comments). So, you can define

\let\ftableTori=\functiontableT
\def\functiontableT#1{\edef\tmp{#1}\expandafter\ftableTori\expandafter{\tmp}}

and you can use

\functiontableT{ 1/4,1/3,1/2,\ForA[1]{1}{9},15}{ 1/#1^2 }
7
  • -@wipet thanks, this works +1. But that's not practical for me from the input. Then you can easily enter the values directly.
    – user139826
    Nov 19, 2017 at 9:19
  • @Thomas What do you mean?
    – Manuel
    Nov 19, 2017 at 12:44
  • @Manuel, wipet's answer is correct because he answers my question. My question was not precise enough. I imagined a faster input. But writing 1,2,3,4,5,6,7,8,9 is probably faster than \edef\x {\noexpand .... \forA [a] {b} {c}...\x. Since I have not formulated the question exactly enough and wipet's answer is correct, I mark it as correct.
    – user139826
    Nov 19, 2017 at 18:51
  • @Thomas Well, that was an example. You can define \functiontableT to automatically carry that expansion.
    – Manuel
    Nov 19, 2017 at 23:06
  • @Manuel that's what I tried. But I did not manage it.
    – user139826
    Nov 20, 2017 at 5:27
1

The complete code for the functiontable with the help of @egreg, who has done the most and the hints of @wipet is

enter image description here

\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} 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy