如何更改真值表中的运算符符号

如何更改真值表中的运算符符号

我需要为我的计算机架构课程输入真值表。到目前为止,我一直在使用手动输入,tabular但今天我发现这是 Scott H 的回答。它提供了一个名为的命令truthtable来自动排版。

类似命令

\truthtable{a,b,c}{a+b;b*(-c);-(a+b)+(b*(-c))}

生产

在此处输入图片描述

现在我想改变逻辑运算符(\vee\wedge\neg),并使用+(或),·(和)和\overline\bar表示不。

排版运算符的函数是:

\cs_new_protected:Npn \__tt_build_header:
    {
        \seq_set_from_clist:NN \l__tt_header_seq \l__tt_vars_clist
        \seq_concat:NNN \l__tt_header_seq \l__tt_header_seq \l__tt_exprs_seq
        \tl_set:Nx \l_tmpa_tl {\seq_use:Nnnn \l__tt_header_seq {&}{&}{&}}
        \tl_replace_all:Nnn \l_tmpa_tl {*} {\wedge}
        \tl_replace_all:Nnn \l_tmpa_tl {+} {\vee}
        \tl_replace_all:Nnn \l_tmpa_tl {->} {\to}
        \tl_replace_all:Nnn \l_tmpa_tl {-} {\neg}
        \tl_use:N \l_tmpa_tl
    }

虽然它是用 LaTeX3 编写的,我看不懂,但用 和 替换很容易\wedge\cdot\vee+不知道是否可以轻松替换\neg以获得带有上划线的符号(或表达式)。我认为这种替代方案很难,居中的波浪号~就足够了。然后我测试了 ,\sim但结果很难看,符号离否定变量或表达式很远。你能帮我找到更好的替代方案吗?

完整代码(需要 lualatex)是

\documentclass{article}
\usepackage{xparse}

\begingroup
  \catcode`\%=12\relax
  \gdef\patmatch{"(%b())->(%b())","!%1||%2"}
\endgroup

\def\setimpaux#1{%
  \directlua{
    local s, _ = string.gsub("\luatexluaescapestring{#1}",\patmatch)
    tex.sprint(s)
  }
}

\ExplSyntaxOn
\int_new:N \l__tt_num_rows_int
\int_new:N \l__tt_num_cols_int
\int_new:N \l__tt_num_vars_int
\clist_new:N \l__tt_vars_clist
\seq_new:N \l__tt_exprs_seq
\seq_new:N \l__tt_header_seq

\NewDocumentCommand {\truthtable}{ m m }
    {
        \truth_table:nn {#1}{#2}
    }

\cs_new_protected:Npn \truth_table:nn #1#2
    {
        \clist_set:Nn \l__tt_vars_clist {#1}
        \seq_set_split:Nnn \l__tt_exprs_seq {;} {#2}
        \int_set:Nn \l__tt_num_vars_int {\clist_count:N \l__tt_vars_clist}
        \int_set:Nn \l__tt_num_rows_int {\fp_to_int:n {2^{\l__tt_num_vars_int}-1}}
        \int_set:Nn \l__tt_num_cols_int {\clist_count:N \l__tt_vars_clist +\seq_count:N \l__tt_exprs_seq}
        \__tt_gen_bins:
        \seq_map_function:NN \l__tt_exprs_seq \__tt_eval_bools:n
        \__tt_build_table:
    }

\cs_new_protected:Npn \__tt_build_header:
    {
        \seq_set_from_clist:NN \l__tt_header_seq \l__tt_vars_clist
        \seq_concat:NNN \l__tt_header_seq \l__tt_header_seq \l__tt_exprs_seq
        \tl_set:Nx \l_tmpa_tl {\seq_use:Nnnn \l__tt_header_seq {&}{&}{&}}
        \tl_replace_all:Nnn \l_tmpa_tl {*} {\wedge}
        \tl_replace_all:Nnn \l_tmpa_tl {+} {\vee}
        \tl_replace_all:Nnn \l_tmpa_tl {->} {\to}
        \tl_replace_all:Nnn \l_tmpa_tl {-} {\neg}
        \tl_use:N \l_tmpa_tl
    }

\cs_generate_variant:Nn \seq_use:Nnnn {cnnn}
\cs_new_protected:Npn \__tt_build_table:
    {
        \begin{array}{*{\int_use:N \l__tt_num_cols_int}{c}}
            \__tt_build_header:\\\hline
            \int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
                {
                    \seq_use:cnnn {l__tt_row_{##1}_seq}{&}{&}{&}\\
                }
        \end{array}
    }

\cs_new_protected:Npn \__tt_set_imp:n #1
    {
        \tl_if_in:nnT {#1} {->}
            {
                \tl_set:Nx \l_tmpb_tl {\setimpaux{#1}}
                \exp_args:NV \__tt_set_imp:n \l_tmpb_tl
            }
    }
\cs_generate_variant:Nn \__tt_set_imp:n {V}

\cs_generate_variant:Nn \tl_replace_all:Nnn {Nnx}
\cs_new_protected:Npn \__tt_eval_bools:n #1
    {
        \tl_set:Nn \l_tmpa_tl {#1}
        \int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
            {
                \int_set:Nn \l_tmpa_int {1}
                \tl_set_eq:NN \l_tmpb_tl \l_tmpa_tl
                \__tt_set_imp:V \l_tmpb_tl
                \tl_replace_all:Nnn \l_tmpb_tl {*}{&&}
                \tl_replace_all:Nnn \l_tmpb_tl {+}{||}
                \tl_replace_all:Nnn \l_tmpb_tl {-}{!}
                \clist_map_inline:Nn \l__tt_vars_clist
                    {
                        \tl_replace_all:Nnx \l_tmpb_tl {####1} {\seq_item:cn {l__tt_row_{##1}_seq} {\l_tmpa_int}}
                        \int_incr:N \l_tmpa_int
                    }
                \seq_put_right:cx {l__tt_row_{##1}_seq} {\fp_eval:n \l_tmpb_tl}
            }
    }

\cs_generate_variant:Nn \seq_set_split:Nnn {cnx}
\cs_new_protected:Npn \__tt_gen_bins:
    {
        \int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
            {
                \seq_clear_new:c {l__tt_row_{##1}_seq}
                \seq_set_split:cnx {l__tt_row_{##1}_seq} {} {\int_to_binary:n {##1}}
                \int_while_do:nn {\seq_count:c {l__tt_row_{##1}_seq} < \l__tt_num_vars_int}
                    {
                        \seq_put_left:cn {l__tt_row_{##1}_seq} {0}
                    }
            }
    }

\ExplSyntaxOff
\begin{document}

\[
\truthtable{a,b,c}{a+b;b*(-c);-(a+b)+(b*(-c))}
\]

\end{document}

答案1

周围不需要的间距\sim来自于这样一个事实:它被定义为使用内核中的\sim关系符号;:\mathrel

\DeclareMathSymbol{\sim}{\mathrel}{symbols}{"18}

您可以使用以下方法将该空格\sim视为普通符号\mathord{\sim}

\cs_new_protected:Npn \__tt_build_header:
    {
        \seq_set_from_clist:NN \l__tt_header_seq \l__tt_vars_clist
        \seq_concat:NNN \l__tt_header_seq \l__tt_header_seq \l__tt_exprs_seq
        \tl_set:Nx \l_tmpa_tl {\seq_use:Nnnn \l__tt_header_seq {&}{&}{&}}
        \tl_replace_all:Nnn \l_tmpa_tl {*} {\cdot}
        \tl_replace_all:Nnn \l_tmpa_tl {+} {+}
        \tl_replace_all:Nnn \l_tmpa_tl {->} {\to}
        \tl_replace_all:Nnn \l_tmpa_tl {-} {\mathord{\sim}}
        \tl_use:N \l_tmpa_tl
    }

完成代码:

\documentclass{article}
\usepackage{xparse}

\begingroup
  \catcode`\%=12\relax
  \gdef\patmatch{"(%b())->(%b())","!%1||%2"}
\endgroup

\def\setimpaux#1{%
  \directlua{
    local s, _ = string.gsub("\luatexluaescapestring{#1}",\patmatch)
    tex.sprint(s)
  }
}

\ExplSyntaxOn
\int_new:N \l__tt_num_rows_int
\int_new:N \l__tt_num_cols_int
\int_new:N \l__tt_num_vars_int
\clist_new:N \l__tt_vars_clist
\seq_new:N \l__tt_exprs_seq
\seq_new:N \l__tt_header_seq

\NewDocumentCommand {\truthtable}{ m m }
    {
        \truth_table:nn {#1}{#2}
    }

\cs_new_protected:Npn \truth_table:nn #1#2
    {
        \clist_set:Nn \l__tt_vars_clist {#1}
        \seq_set_split:Nnn \l__tt_exprs_seq {;} {#2}
        \int_set:Nn \l__tt_num_vars_int {\clist_count:N \l__tt_vars_clist}
        \int_set:Nn \l__tt_num_rows_int {\fp_to_int:n {2^{\l__tt_num_vars_int}-1}}
        \int_set:Nn \l__tt_num_cols_int {\clist_count:N \l__tt_vars_clist +\seq_count:N \l__tt_exprs_seq}
        \__tt_gen_bins:
        \seq_map_function:NN \l__tt_exprs_seq \__tt_eval_bools:n
        \__tt_build_table:
    }

\cs_new_protected:Npn \__tt_build_header:
    {
        \seq_set_from_clist:NN \l__tt_header_seq \l__tt_vars_clist
        \seq_concat:NNN \l__tt_header_seq \l__tt_header_seq \l__tt_exprs_seq
        \tl_set:Nx \l_tmpa_tl {\seq_use:Nnnn \l__tt_header_seq {&}{&}{&}}
        \tl_replace_all:Nnn \l_tmpa_tl {*} {\cdot}
        \tl_replace_all:Nnn \l_tmpa_tl {+} {+}
        \tl_replace_all:Nnn \l_tmpa_tl {->} {\to}
        \tl_replace_all:Nnn \l_tmpa_tl {-} {\mathord{\sim}}
        \tl_use:N \l_tmpa_tl
    }

\cs_generate_variant:Nn \seq_use:Nnnn {cnnn}
\cs_new_protected:Npn \__tt_build_table:
    {
        \begin{array}{*{\int_use:N \l__tt_num_cols_int}{c}}
            \__tt_build_header:\\\hline
            \int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
                {
                    \seq_use:cnnn {l__tt_row_{##1}_seq}{&}{&}{&}\\
                }
        \end{array}
    }

\cs_new_protected:Npn \__tt_set_imp:n #1
    {
        \tl_if_in:nnT {#1} {->}
            {
                \tl_set:Nx \l_tmpb_tl {\setimpaux{#1}}
                \exp_args:NV \__tt_set_imp:n \l_tmpb_tl
            }
    }
\cs_generate_variant:Nn \__tt_set_imp:n {V}

\cs_generate_variant:Nn \tl_replace_all:Nnn {Nnx}
\cs_new_protected:Npn \__tt_eval_bools:n #1
    {
        \tl_set:Nn \l_tmpa_tl {#1}
        \int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
            {
                \int_set:Nn \l_tmpa_int {1}
                \tl_set_eq:NN \l_tmpb_tl \l_tmpa_tl
                \__tt_set_imp:V \l_tmpb_tl
                \tl_replace_all:Nnn \l_tmpb_tl {*}{&&}
                \tl_replace_all:Nnn \l_tmpb_tl {+}{||}
                \tl_replace_all:Nnn \l_tmpb_tl {-}{!}
                \clist_map_inline:Nn \l__tt_vars_clist
                    {
                        \tl_replace_all:Nnx \l_tmpb_tl {####1} {\seq_item:cn {l__tt_row_{##1}_seq} {\l_tmpa_int}}
                        \int_incr:N \l_tmpa_int
                    }
                \seq_put_right:cx {l__tt_row_{##1}_seq} {\fp_eval:n \l_tmpb_tl}
            }
    }

\cs_generate_variant:Nn \seq_set_split:Nnn {cnx}
\cs_new_protected:Npn \__tt_gen_bins:
    {
        \int_step_inline:nnnn {0}{1}{\l__tt_num_rows_int}
            {
                \seq_clear_new:c {l__tt_row_{##1}_seq}
                \seq_set_split:cnx {l__tt_row_{##1}_seq} {} {\int_to_binary:n {##1}}
                \int_while_do:nn {\seq_count:c {l__tt_row_{##1}_seq} < \l__tt_num_vars_int}
                    {
                        \seq_put_left:cn {l__tt_row_{##1}_seq} {0}
                    }
            }
    }

\ExplSyntaxOff
\begin{document}

\[
\truthtable{a,b,c}{a+b;b*(-c);-(a+b)+(b*(-c))}
\]

\end{document}

在此处输入图片描述

\mathord关于、\mathrel和类似词的解释\mathbin可以在TeX 按主题分类电子书

答案2

兼容性更新

  • release1.2l (2017/07/26)删除了我在这里使用的内部宏 ( \xint_gob_til_xint_relax)。因此我添加了定义以使代码再次编译。

  • (2015/03/07)自发布1.1 (2014/10/28)以来信特\xintNewExpr这个答案的原始代码被破坏了。用户手册中提到了 的全面修改,但它应该被列入 的“重大更改”列表中CHANGES.html。 实际上,只有 的一个非常深奥的功能的\xintNew(Bool)Expr更改影响了这里的代码,我忘了世界上存在这种用途!

xint < 1.1 对于使用旧代码的人来说,代码还在那里,但是被注释掉了。

顺便说一下,我提到现在逻辑运算&&符“和”比“与”更|| 受欢迎,但后者仍然被接受,尽管也许它们将来会用于其他用途:也许是按位运算。xint&|


这是该方法的一个(适度的)替代方案LaTeX3+lualatex。它使用xintexpr。它要求用户在逻辑表达式中使用\AND\OR、 。其他关键字有、、。\NOT\XOR\ALL\ANY


最新更新:变量的数量无论如何都限制为9,因为每个表达式都将转换为具有那么多参数的宏。因此,第一个带有嵌套的答案\xintFor,其拼写为最多5变量,在这种情况下具有完全通用的潜力。但是在我的第二个答案(这个答案的底部)中,我以类似于我在代码中看到的方法的方式生成行LaTeX3+lualatex,通过对整数进行二进制扩展01...最多为2^n-1n变量数量。这使得编码更紧凑(效率也更低,但这并不重要)。

第二个答案另外添加了一个可选参数,允许用户直接指定表达式在标题行中的显示方式。

此外,它也允许最后的表达式以 结尾;

而且,星号变体使用\halign而不是array环境来允许分页。对于9变量,会512生成行,因此这是必要的。图像只是包含行的文档的第一页12


更新:使用;(如 OP 中所示)而不是,分隔表达式。

布尔表达式使用\AND、来输入\OR\NOT还有\XOR\ALL\ANY(它们有多个参数,以 分隔,)。然后可以在宏中自定义如何排版它们。

布尔表达式被分隔(如在 OP 中一样)分号:我最初的答案使用了逗号,因为\xintexpr解析器本身可以处理这个问题,当在其他地方使用逗号分隔函数参数时也是如此。但是,为了排版第一行,必须用括号(例如 )或 隐藏这些逗号,\XOR({a,b,c})不太\XOR(a\SEP b\SEP c)方便\def\SEP{,}。因此,用户输入中的表达式现在使用 分隔;

可以看出,这里的代码很短。最后我有点精疲力竭,也许有办法将其缩短一点,避免使用大\ifcase。就目前而言,代码允许构建一个表,其中最多有5表示为字母的不确定项(扩大\ifcase可能最多有95字母已经有32行)和任意多个用逗号分隔的布尔表达式(实际上,就目前而言,表达式的 nb 加上 不确定项的 nb 最多应保持为10,请参阅*{10}c数组前言)[我没有时间检查是否可以10用动态的东西替换,在这种情况下,从两个参数计算它没有问题\truthtable]

真值表

另外两个真值表:

更多真值表

\documentclass{article}
\usepackage{xintexpr}

\catcode`_ 11

\newcount \tt_varcnt

% this internal macro was suppressed in xint 1.2l (2017/07/26)
% but is used in this answer
\long\def\xint_gob_til_xint_relax #1\xint_relax {}%
\let\xint_relax\relax

% auxiliary macro to handle things separated by semi-colons
\def\truthtable_scanexprs #1;{%
    \xint_gob_til_xint_relax #1\truthtable_scan_done\xint_relax
    \odef\tt_exprlist {\tt_exprlist{#1}}%
    \truthtable_scanexprs
}%
\def\truthtable_scan_done #1\truthtable_scanexprs {}                           

\newcommand\truthtable [2]{%
% example of use :
% \truthtable{a,b,c}{a\OR b; b\AND\NOT(c)}
%
% The first argument lists the used indeterminates, they must be lowercase or
% uppercase Latin letters.
% 
% The second argument is a ; separated list of logical expressions.
  \begingroup
    \endlinechar-1 \everyeof{\noexpand }% for use of \scantokens
    % initializing
    \tt_varcnt 0
    \def\tt_exprlist {}% will be {exprA}{exprB}{exprC}...
    % scan #2 for ; separated expressions and fill \tt_exprlist:
    \truthtable_scanexprs #2;\xint_relax;%
    %
    % PREPARATION FOR DEFINING THE BOOLEAN EXPRESSIONS
% MODIFIED FOR COMPATIBILITY WITH xint 1.1 OR LATER
%%%% | and & are still accepted but the manual recommend || and &&
%%%%  (2015/03/07)
    \def\OR{||}\def\AND{&&}\def\NOT{!}% needed for \xintNewBoolExpr
% original was
    % \def\OR{|}\def\AND{&}\def\NOT{!}% needed for \xintNewBoolExpr
% END
    % the negation ! must be applied to a parenthesized expression
    % 
    % extra strange set-up before \edef and then \scantokens
    % the idea is too allow, X, O, R, A, L, L, A, N, Y as indeterminates...
    % ... and for this as we will need to make them active, thus
    %     we must first replace \XOR for example by \1.
    \def\XOR{\1}\def\ALL{\2}\def\ANY{\3}%
    \let\1\relax\let\2\relax\let\3\relax
    %
    \edef\tt_x {\tt_exprlist}% replaces \XOR by \1, \ALL by \2, \ANY by \3
    %
% ORIGINAL VERSION:
    % % we now make active the indeterminates to replace them by {$1}, {$2}, ..
    % % place holders (cf.  xintexpr manual)
    % \xintFor ##1 in {#1} \do 
    %   {\catcode`##1\active
    %    \advance\tt_varcnt 1
    %    \lccode`~=`##1\relax
    %    \lowercase{\edef~}{{$\the\tt_varcnt}}%$1, $2, $3, as in xintexpr manual
    % }%
% NEW VERSION FOR COMPATIBILITY WITH xint 1.1 OR LATER  (2015/03/07)
    % we now make active the indeterminates to replace them by {#1}, {#2}, ..
    % place holders (with a catcode 12 # as it simplifies things here, and
    % the \xintNewExpr scanner does not mind)
    \xintFor ##1 in {#1} \do% 
    % I should have defined a sub-macro for this, code would be clearer
        {\catcode`##1\active
         \advance\tt_varcnt 1
         \lccode`~=`##1\relax
         \lowercase{\edef~}{{\string####\the\tt_varcnt}}}%
% END OF MODIFICATION
    %
    % Now \scantokens to replace the now active letters by the braced
    % macro parameters (I don't recall exactly why I wanted them braced,
    % these braces will get removed during \xintNewExpr scan)
    %
    \edef\tt_x {\scantokens\expandafter{\tt_x}}%
    %
    % For use of \xintNewBoolExpr (which again does some \scantokens), 
    % the letters *must* be reset to their standard catcodes.
    %
    \xintFor ##1 in {#1} \do {\catcode`##1 11 }% 
    %
    % Definition of the boolean expressions. Using ; as separator for
    % user input was only in order to ease up
% NOTE: (2015/03/07)
% for simplicity I stick here to the originally used ; as expression separator
% on input, but xint 1.1 has macros which can be used, out of \xintexpr
% context to identify (expandably) comma separated things, even themselves
% containing commas if they are in parentheses
    % finding the correct
    % expressions for typesetting the head-row of the table, we need to
    % re-install here the , as separator, this allows to do only one
    % \xintNewBoolExpr, as it knows how to identify the various 
    % comma separated sub-expressions.
    %
    \def\1{xor}\def\2{all}\def\3{any}%
    \xintNewBoolExpr\tt_y[\tt_varcnt]{\xintListWithSep{,}{\tt_x}}%
    % 
    % CUSTOMIZE HERE:
    % For typesetting the head row, customize as desired:
    \def\OR{+}\def\AND{\cdot}\def\NOT{\mathord{\sim}}%
    \def\XOR{\mbox{\texttt{xor}}}%
    \def\ALL{\mbox{\texttt{all}}}%
    \def\ANY{\mbox{\texttt{any}}}%
    %
    % the table. Up to five variables, extensible up to use of nine variables
    \begin{array}{*{10}c}
       \xintListWithSep{&}{\xintCSVtoList{#1}}&%
                                 \xintListWithSep{&}{\tt_exprlist}\\
       \hline
       \ifcase\tt_varcnt
       \or
       \xintFor* ##1 in {01}\do
       {##1 & \xintListWithSep{&}{\xintCSVtoList{\tt_y {##1}}}\\ }
       \or
       \xintFor* ##1 in {01}\do
       {\xintFor* ##2 in {01}\do
        {##1 & ##2& 
           \xintListWithSep{&}{\xintCSVtoList{\tt_y {##1}{##2}}}\\ }}
       \or
       \xintFor* ##1 in {01}\do
       {\xintFor* ##2 in {01}\do
        {\xintFor* ##3 in {01}\do
         {##1 & ##2 & ##3& \xintListWithSep{&}%
                           {\xintCSVtoList{\tt_y {##1}{##2}{##3}}}\\ }}}
       \or
       \xintFor* ##1 in {01}\do
       {\xintFor* ##2 in {01}\do
        {\xintFor* ##3 in {01}\do
         {\xintFor* ##4 in {01}\do
          {##1 & ##2 & ##3& ##4&\xintListWithSep{&}%
                           {\xintCSVtoList{\tt_y {##1}{##2}{##3}{##4}}}\\ }}}}
       \or
       \xintFor* ##1 in {01}\do
       {\xintFor* ##2 in {01}\do
        {\xintFor* ##3 in {01}\do
         {\xintFor* ##4 in {01}\do
          {\xintFor* ##5 in {01}\do
          {##1 & ##2 & ##3& ##4& ##5&\xintListWithSep{&}%
                      {\xintCSVtoList{\tt_y {##1}{##2}{##3}{##4}{##5}}}\\ }}}}}
       \fi
       \hline 
    \end{array}
    \endgroup
}
\catcode`_ 8   

\begin{document}

\[
\truthtable{a,b,c}{a\OR b; b\AND\NOT(c); \NOT (a\OR b)\OR (b\AND\NOT(c))}
\]

\[
\truthtable{X,Y,Z}{Z\AND X \OR Y \AND X}
\]

\[
\truthtable{X,Y,Z,T}{Z\AND X \OR Y \AND X \AND T}
\]

\[
\truthtable{a, b}{\XOR (a,b)}
\]

\[
\truthtable {p, q, r, s, t}{\ANY(p,q,r,s,t); \XOR(p,q,r,s,t); \ALL(p,q,r,s,t)}
\]

\[
\truthtable{a, b, c, d}{\XOR (a,b,c,d); \XOR(a,\XOR(b,c,d)); \XOR(\XOR(a,b),\XOR(c,d))}
\]

\[
\truthtable{A,D,N}{A\AND D \OR N \AND D; A\OR D \AND N \OR D}
\]

\end{document}

这是第二个答案的代码:

\documentclass[a4paper]{article}
\usepackage{geometry}
\usepackage{xintexpr}
% in order to convert from decimal to binary using \xintDecBin
\usepackage{xintbinhex}

\catcode`_ 11
\makeatletter

% to count the number of variables:
\newcount \tt_varcnt
% The number of variables is at most 9 (leading to 512 rows...)

% to count the number of expressions (in order to choose dynamically
% a large enough number of columns for the array environment)
\newcount \tt_exprcnt

% to handle things separated by semi-colons

% we add some extra to allow empty expressions to be skipped, and also to allow
% the user to terminate the last expression by a ; 

% [if the optional parameter is used, use \space to get something empty in the
% header row cell]

% this internal macro was suppressed in xint 1.2l (2017/07/26)
% but is used in this answer
\long\def\xint_gob_til_xint_relax #1\xint_relax {}%
\let\xint_relax\relax

\def\truthtable_scanexprs #1;{%
    \if\relax\detokenize{#1}\relax\expandafter\truthtable_scan_skip\fi
    \xint_gob_til_xint_relax #1\truthtable_scan_done\xint_relax
    \odef\tt_exprlist {\tt_exprlist{#1}}%
    \advance \tt_exprcnt 1
    \truthtable_scanexprs
}%
\def\truthtable_scan_done #1\truthtable_scanexprs {}%                     
\def\truthtable_scan_skip #1\truthtable_scanexprs {\truthtable_scanexprs}%

% we now have an optional parameter to provide a custom typesetting
% of the expressions in the head row

% and we have furthermore a star variant to use \halign rather than array

\newcommand*\truthtable {%
   \begingroup
     \endlinechar-1 \everyeof{\noexpand }% for use of \scantokens
     \tt_varcnt 0
     \tt_exprcnt 0
     \def\tt_exprlist {}%
     \def\tt_headexprlist {\tt_exprlist}%
     \def\tt_usearray {1}%
     \@ifstar{\def\tt_usearray {0}\truthtable@chkopt}\truthtable@chkopt
}%

\def\truthtable@chkopt {\@ifnextchar[{\truthtable@opt}{\truthtable@}%]
                       }

\def\truthtable@opt [#1]{%
      % we first scan the optional argument for the header row.
      % it will be printed as is, only need to transform the ;'s into &'s
      \truthtable_scanexprs #1;\xint_relax;%
      \let\tt_headexprlist\tt_exprlist
      \tt_exprcnt 0
      \def\tt_exprlist {}%
      \truthtable@
      % *NO* check is done that #1 defines the same number of expressions
      % as the last mandatory argument to \truthtable !
}

\def\truthtable@ #1#2{%
    % convert the comma separated indeterminates into a list
    \oodef\tt_varlist{\xintCSVtoListNoExpand {#1}}%
    % scan #2 for ; separated expressions and fill \tt_exprlist:
    \truthtable_scanexprs #2;\xint_relax;%
    % PREPARATION FOR DEFINING THE BOOLEAN EXPRESSIONS
% MODIFIED FOR COMPATIBILITY WITH xint 1.1 OR LATER
%%%% | and & are still accepted but the manual recommend || and &&
%%%%  (2015/03/07)
    \def\OR{||}\def\AND{&&}\def\NOT{!}% needed for \xintNewBoolExpr
% original was
    % \def\OR{|}\def\AND{&}\def\NOT{!}% needed for \xintNewBoolExpr
% END
    % the negation ! must be applied to a parenthesized expression
    % 
    % extra strange set-up before \edef and then \scantokens
    % the idea is too allow, X, O, R, A, L, L, A, N, Y as indeterminates...
    % ... and for this as we will need to make them active, thus
    %     we must first replace \XOR for example by \1.
    \def\XOR{\1}\def\ALL{\2}\def\ANY{\3}%
    \let\1\relax\let\2\relax\let\3\relax
    %
    \edef\tt_x {\tt_exprlist}%  replaces \XOR by \1, \ALL by \2, \ANY by \3
    %
% ORIGINAL VERSION:
    % % we now make active the indeterminates to replace them by {$1}, {$2}, ..
    % % place holders (cf.  xintexpr manual)
    % \xintFor ##1 in {#1} \do 
    %   {\catcode`##1\active
    %    \advance\tt_varcnt 1
    %    \lccode`~=`##1\relax
    %    \lowercase{\edef~}{{$\the\tt_varcnt}}%$1, $2, $3, as in xintexpr manual
    % }%
% NEW VERSION FOR COMPATIBILITY WITH xint 1.1 OR LATER  (2015/03/07)
    % we now make active the indeterminates to replace them by {#1}, {#2}, ..
    % place holders (with a catcode 12 # as it simplifies things here, and
    % the \xintNewExpr scanner does not mind)
    \xintFor ##1 in {#1} \do% 
    % I should have defined a sub-macro for this, code would be clearer
        {\catcode`##1\active
         \advance\tt_varcnt 1
         \lccode`~=`##1\relax
         \lowercase{\edef~}{{\string####\the\tt_varcnt}}}%
% END OF MODIFICATION
    % Now the \scantokens with active letters. 
    \edef\tt_x {\scantokens\expandafter{\tt_x}}%
    %
    % For use of \xintNewBoolExpr (which again does some \scantokens), 
    % the letters *must* recover their standard catcodes
    %
    \xintFor* ##1 in \tt_varlist \do {\catcode`##1 11 }% 
    %
    % Definition of the boolean expressions. Using ; as separator for
    % user input was only in order to ease up finding the correct
    % expressions for typesetting the head-row of the table, we need to
    % re-install here the , as separator, this allows to do only one
    % \xintNewBoolExpr, it knows how to identify the various sub-expressions.
    \def\1{xor}\def\2{all}\def\3{any}%
    \xintNewBoolExpr\tt_y[\tt_varcnt]{\xintListWithSep{,}{\tt_x}}%
    % 
    % CUSTOMIZE HERE:
    % For typesetting the head row, customize as desired:
    % (*not* relevant in case of use of the optional parameter)
    \def\OR{+}\def\AND{\cdot}\def\NOT{\mathord{\sim}}%
    \def\XOR{\mbox{\texttt{xor}}}%
    \def\ALL{\mbox{\texttt{all}}}%
    \def\ANY{\mbox{\texttt{any}}}%
    %
    \if\tt_usearray 1\expandafter\truthtable_array\else
                     \expandafter\truthtable_halign
    \fi
    \endgroup
}

\def\truthtable_array {%
    % (we have the count of variables in \tt_varcnt and the count of 
    %  expressions in \tt_exprcnt)
    \begin{array}{*{\numexpr\tt_varcnt+\tt_exprcnt\relax}c}
       % generate the header-row, 
         \xintListWithSep{&}{\tt_varlist}
       &
         \xintListWithSep{&}{\tt_headexprlist}\\
       \hline
       % calculate 2^n, n is nb of variables
       \tt_varcnt \xintiiPow {2}{\tt_varcnt} 
       % generate integers from 2^n  to 2*2^n -1, then binary notation
       % will always start by a 1 which we can gobble
       \xintFor* ##1 in {\xintSeq {\tt_varcnt}{2*\tt_varcnt-1}}
       \do
       %    (the problem is that \xintDecToBin always trims leading zeros...
       %     hence we resort to this to always have a leading 1)
       {\edef\tt_temp{\expandafter\expandafter\expandafter
                      \xint_gobble_i\xintDecToBin {##1}}%
        \edef\tt_temp{\tt_temp\xintCSVtoList{\expandafter\tt_y\tt_temp}}%
        \xintListWithSep {&}{\tt_temp}\\}
       \hline 
    \end{array}
}

\newtoks\tt_toks

% The \halign variant (should *not* be put inside \[..\])
\def\truthtable_halign {%
    % This is variant using \halign to allow break accross pages.
    % I use some tricks to center it (whow! incredibly it works)
    % (I initially used a repeatable preamble, but following TeX by Topic
    %  25.5, to center the alignment, I need to insert some \tabskip
    %  at the LAST column, hence here I follow a more complicated approach
    %  constructing the preamble first.)
    %  
    % but then I don't know how to have horizontal rules limited to
    % the width covered by the actual contents... 
    %
    \tt_toks {\hfil$\mathstrut##$\hfil\tabskip 2\arraycolsep}%
    \xintiloop [{\tt_varcnt+\tt_exprcnt-1}+-1]
    \ifnum\xintiloopindex>0
      \tt_toks \expandafter{\the\tt_toks &\hfil$##$\hfil}%
    \repeat
    %\showthe\tt_toks
    \tabskip 0pt plus 1000pt minus 1000pt 
    \halign to \hsize
    {\span\the\tt_toks\tabskip 0pt plus 1000pt minus 1000pt \cr
     % first row
     \xintListWithSep{&}{\tt_varlist}&\xintListWithSep{&}{\tt_headexprlist}\cr
     % however the rule extends across the full page
     %     \hline
     \tt_varcnt \xintiiPow {2}{\tt_varcnt} 
     \xintFor* ##1 in {\xintSeq {\tt_varcnt}{2*\tt_varcnt-1}}
       \do
       {\edef\tt_temp{\expandafter\expandafter\expandafter
                      \xint_gobble_i\xintDecToBin {##1}}%
        \edef\tt_temp{\tt_temp\xintCSVtoList{\expandafter\tt_y\tt_temp}}%
        \xintListWithSep {&}{\tt_temp}\cr }%
     %      \hline 
    }%
}

\catcode`_ 8   
\makeatother

\pagestyle{empty}
\begin{document}\thispagestyle{empty}

\[
\truthtable{a,b,c}{a\OR b; b\AND\NOT(c); \NOT (a\OR b)\OR (b\AND\NOT(c));}
\]


\textbf{Exercise:~} fill in the header row:

\[% in the optional argument, \AND, \NOT, are not mandatory but optional
  % on can use whatever one wants.
\truthtable [a?b; ?\cdot\NOT(c); \NOT(a+?)?(b\AND\NOT(?));]% trailing ; allowed
            {a, b, c}
            {a\OR b; b\AND\NOT(c); \NOT (a\OR b)\OR (b\AND\NOT(c))}
\]


% maximal number of variables is 9

% \truthtable* {a, b, c}{\XOR(a, b, c)}
\bigskip
\hrule
\medskip
An example with the maximal number of variables (9, hence 512 rows) using
\verb|\halign| to allow breaking accross pages:\medskip

\truthtable* [\XOR(a,\cdots,i); ?(a,\cdots,d)\AND\NOT(?(e,\cdots,i));]
             {a, b , c, d, e, f, g, h, i}
             {\XOR(a, b , c, d, e, f, g, h, i); 
              \ALL(a,b,c,d)\AND\NOT(\ANY(e,f,g,h,i))
            }

\end{document}

真值表...

答案3

我提供另一个答案有两个原因:

  1. 自 2015 年秋季起,xint可以发布一种更简单的方法;不需要激活字母来扫描变量。

  2. 这种更简单的方法也更强大:不需要使用\AND\OR等宏来格式化输入;它可以在理解的语法中给出\xintexpr。然后就可以用合适的符号来评估和格式化原始表达式。

  3. 在对第一个答案的评论中,有人问如何添加更多运算符。无法处理语法中未知的二进制中缀逻辑运算符xintexpr。但有些运算符可以通过比较运算符来模拟。人们确实使用\IFF等符号,不是因为它是强制性的,而是因为带有比较运算符(在输入时)的符号不直观。

更多解释请参见代码注释。

(更新仅涉及实现和代码注释的一些细节变化)

\documentclass[a4paper]{article}

\usepackage{geometry}
\usepackage{xintexpr}

\usepackage{newtxtext,newtxmath}
\usepackage[straightquotes]{newtxtt}

\usepackage{longtable, array, color, bm}% Thanks to D.C.
\setlength{\LTcapwidth}{\textwidth}

\makeatletter
% Utility macro to use directly the underlying macro foo with variables bar
% as defined earlier  by \xintdeffunc foo(bar):=...;
\newcommand*\UseUserFuncMacro [2]{\csname XINT_expr_userfunc_#1\endcsname #2,}

% Define logical values:
\xintdefvar T:= 1;
\xintdefvar F:= 0;

% We will use input with control sequences \AND, etc.. 


% The mechanism of the Truth Table necessitates that the xintexpr syntax
% has some infix binary operator pre-assigned to the given operation

% This is currently the case for AND, OR, XOR (and NOT as function).

% Currently there is no available operator for things such as 
% NOR, NAND, XNOR.

% **This will have to wait for a future package release.**

% Some operations can be simulated by comparison operators

% IFF             can be simulated by =
% IMPLIES         can be simulated by <=
% IS IMPLIED BY   can be simulated by >=
% DOES NOT IMPLY  can be simulated by >
% IS NOT IMPLIED  can be simulated by <
% IS NOT EQUIV.   can be simulated by != but same as XOR

% BUT THE PRECEDENCE LEVELS MUST BE MODIFIED. 

% This is easier than adding a new infix operator to the xintexpr syntax. 

% Changing precedences could have been a one-liner but unfortunately xintexpr
% (1.2e) has some unnecessarily hard-coded things. Thus we have to do some
% redefinitions. Adding genuine new operators rather than abusing already
% existing ones would require a few more definitions, but this is best left to
% a package upgrade.

% ----

% The approach here is to code the formulas with macros \IFF, \IMP, \ISIMP,
% \NIMP, \NISIMP. For coherence also \AND, \OR, \XOR,  will be defined, but
% direct use of the &&, 'and, ||, 'or', 'xor' is possible.

% The input expressions will be used for two things :

% 1. format the expression with suitable math mode symbols
% 2. evaluate logic expressions.

% **** Control sequences \IFF etc... in the input are only needed due to the
% fact that direct use of the ersatz <=, <, >, >= gives counterintuitive
% looking formulas on input. ****

% The \NOT has a **mandatory** parenthesized argument and \NOT(P), not(P),
% !(P) are equivalent.


% In the following it would have been more efficient to use "iiexpr",
% "\xintdefiifunc", "\xintiiLtorEq", etc ...but there is a bug in
% current xint (1.2e): the macros associated to == and <= by
% \xintiiexpr were forgotten for inclusion in the
% \xintdefiifunc/xintNewIIExpr mechanism. Hence we must use \xintexpr.

% Because they may be used in captions etc...
% ************ Although here I have used a \detokenize 
% ************ to allow for example also &&, hence it is
% ************ not so much needed to have the \AND etc robust
\DeclareRobustCommand*\AND{\string\AND\space}
\DeclareRobustCommand*\OR{\string\OR\space}
\DeclareRobustCommand*\NOT{\string\NOT\space}
\DeclareRobustCommand*\XOR{\string\XOR\space}
\DeclareRobustCommand*\IMP{\string\IMP\space}% <=
\DeclareRobustCommand*\ISIMP{\string\IMP\space}% >=
\DeclareRobustCommand*\NIMP{\string\NIMP\space}% >
\DeclareRobustCommand*\NISIMP{\string\NISIMP\space}% <
\DeclareRobustCommand*\IFF{\string\IFF\space}% =
%\DeclareRobustCommand*\NIFF{\string\NIFF\space}% =
\def\T{T}

% Note that use of \AND, \OR, \NOT, \XOR, is optional
% one can use 'and', 'or', 'xor' (quotes mandatory) and not or ! (no quotes,
% necessarily with parentheses not(P), !(Q) for example)
\newcommand{\TruthTableParseSyntaxOn}
% to be used in a group or environment
{\def\AND{&}% would prefer && and ||, but & diminishes the needed work in
            % AdjustPrecedences (which should not have been needed, but well).
 \def\OR{|}%
 \def\NOT{!}% used as function \NOT(P), parentheses mandatory
 \def\XOR{'xor'}% infix binary, there is also multi-variable function xor(..)
 \def\IMP{<=}\def\ISIMP{>=}\def\NIMP{>}\def\NISIMP{<}%
 \def\IFF{=}%
}
\newcommand{\TruthTableParseSyntaxOff}
{\edef\AND  {\expandafter\noexpand\csname AND \endcsname}%
\edef\OR    {\expandafter\noexpand\csname OR \endcsname}%
\edef\NOT   {\expandafter\noexpand\csname NOT \endcsname}%
\edef\XOR   {\expandafter\noexpand\csname XOR \endcsname}%
\edef\IMP   {\expandafter\noexpand\csname IMP \endcsname}%
\edef\ISIMP {\expandafter\noexpand\csname ISIMP \endcsname}%
\edef\NIMP  {\expandafter\noexpand\csname NIMP \endcsname}%
\edef\NISIMP{\expandafter\noexpand\csname NISIMP \endcsname}%
\edef\IFF   {\expandafter\noexpand\csname IFF \endcsname}%
}

% Let's now do the adjustment to infix operator precedences.

\catcode`_ 11
\catcode`& 11
\catcode`| 11
\catcode`< 11
\catcode`> 11
\catcode`= 11
\newcommand*\TruthTableAdjustPrecedences
{% to be used preferably in a group or environment as it impacts other
 % xintexpr contexts.
% The ! is always used with function syntax !(P), and as such has 
% automatically highest precedecence. Hence no change needed here for !.
 \let\XINT_expr_precedence_&  \xint_c_vi  % 6 : a high precedence
 \let\XINT_expr_precedence_|  \xint_c_v   % 5
 \let\XINT_expr_precedence_xor\xint_c_vi  % same as AND
 \let\XINT_expr_precedence_<= \xint_c_iv  % implies
 \let\XINT_expr_precedence_>= \xint_c_iv  % is implied by
 \let\XINT_expr_precedence_>  \xint_c_iv   % does not imply
 \let\XINT_expr_precedence_<  \xint_c_iv   % is not implied by
 \let\XINT_expr_precedence_=  \xint_c_iii  % iff : lowest precedence
 % Unfortunately the above is not enough because xintexpr currently
 % stupidly uses at some spot \xint_c_... constants rather than the
 % precedence control sequences above. Using etoolbox's \patchcmd is
 % not easily done due to special catcodes (in particular & must be
 % used with two distinct catcodes...) Must do brute force
 % redefinitions.
 \XINT_Redefine {&}{\xintAND}%
 \XINT_Redefine {|}{\xintOR}%
 \XINT_Redefine {xor}{\xintXOR}%
 \XINT_Redefine {<=}{\xintLtorEq}%
 \XINT_Redefine {>=}{\xintGtorEq}%
 \XINT_Redefine {<}{\xintLt}%
 \XINT_Redefine {>}{\xintGt}%
 \XINT_Redefine {=}{\xintEq}%
}%
\catcode`& 4
\catcode`| 12
\catcode`< 12
\catcode`> 12
\catcode`= 12

\def\XINT_Redefine #1{%
    \expandafter\XINT_Redefine_a
    \csname XINT_expr_until_#1_b\expandafter\endcsname
    \csname XINT_expr_until_#1_a\expandafter\endcsname
    \csname XINT_expr_precedence_#1\endcsname
}

\def\XINT_Redefine_a #1#2#3#4{%
  \def#1##1##2##3##4{\ifnum ##2>#3%
    \xint_afterfi {\expandafter #2\expandafter ##1%
     \romannumeral`\^^@\csname XINT_expr_op_##3\endcsname {##4}}%
   \else 
    \xint_afterfi {\expandafter ##2\expandafter ##3%
      \csname .=#4{\XINT_expr_unlock ##1}{\XINT_expr_unlock ##4}\endcsname }%
   \fi }%
}
\catcode`_ 8


% This section takes care of how the logic operators will be formatted
% to display the evaluated formula.
\catcode`: 11
% \newcommand{\TruthTableFormattingOn}
% % to be used in a group
% {%
%  \renewcommand*\xintAND[2]{##1\land ##2}%
%  \renewcommand*\xintOR[2]{##1\lor ##2}%
%  \renewcommand*\xintiiIsZero[1]{\neg ##1}%
%  \renewcommand*\xintXOR[2]{##1\mathbin{\mathrm{xor}}##2}%
%  \renewcommand*\xintLtorEq[2]{##1 \Rightarrow ##2}%
%  \renewcommand*\xintGtorEq[2]{##1 \Leftarrow ##2}%
%  \renewcommand*\xintLt[2]{##1 \nLeftarrow ##2}%
%  \renewcommand*\xintGt[2]{##1 \nRightarrow ##2}%
%  \renewcommand*\xintEq[2]{##1 \Leftrightarrow ##2}%
%  \renewcommand*\xintANDof:csv[1]{{\mathrm{all}(##1)}}% hide sub commas from \xintFor's sight
%  \renewcommand*\xintORof:csv[1] {{\mathrm{any}(##1)}}%
%  \renewcommand*\xintXORof:csv[1]{{\mathrm{xor}(##1)}}%
% }%

\newcommand{\TruthTableFormattingOnWithParens}
% to be used in a group
{% parentheses added to display precedence levels
% But we want to remove outermost parentheses.
% This will use a trick. The definition of \EncloseInParen below
% is done to 1) survive \edef, 2) compatible with full first expansion
% done by \UseUserFuncMacro, 3) allow easy removal of outermost ones if
% present.
% 
% ADDED NOTE: code in \TruthTable does not use an \edef anymore, hence it is
% not anymore needed for the stuff here to be \edef compatible.
% 
 \renewcommand*\xintAND[2]{\EncloseInParen{##1\land ##2}}%
 \renewcommand*\xintOR[2]{\EncloseInParen{##1\lor ##2}}%
 \renewcommand*\xintiiIsZero[1]{\neg ##1}%
 \renewcommand*\xintXOR[2]{\EncloseInParen{##1\mathbin{\mathrm{xor}}##2}}%
 \renewcommand*\xintLtorEq[2]{\EncloseInParen{##1 \Rightarrow ##2}}%
 \renewcommand*\xintGtorEq[2]{\EncloseInParen{##1 \Leftarrow ##2}}%
 \renewcommand*\xintLt[2]{\EncloseInParen{##1 \nLeftarrow ##2}}%
 \renewcommand*\xintGt[2]{\EncloseInParen{##1 \nRightarrow ##2}}%
 \renewcommand*\xintEq[2]{\EncloseInParen{##1 \Leftrightarrow ##2}}%
% There are braces here to hide commas from \xintFor on one occasion below
 \renewcommand*\xintANDof:csv[1]{{\mathrm{all}(##1)}}%
 \renewcommand*\xintORof:csv[1] {{\mathrm{any}(##1)}}%
 \renewcommand*\xintXORof:csv[1]{{\mathrm{xor}(##1)}}%
}%
\catcode`: 12

\newcommand*\EncloseInParen  {\relax\noexpand\EncloseInParen@i}
\newcommand*\FixParen [1]{\ifx\relax#1\expandafter\@gobbletwo\fi #1}
\newcommand*\EncloseInParen@i [1]
  {\mathopen{{\color{blue}\bm(}}#1\mathclose{{\color{blue}\bm)}}}

% unfortunately can't bolden delimiters directly with \bm
% \newcommand*\EncloseInParen@i [1]
%   {\mathopen{{\color{blue}\bm{\big(}}}#1\mathclose{{\color{blue}\bm{\big)}}}}
% unfortunately can't bolden delimiters with \bm
% \newcommand*\EncloseInParen@i [1]
%   {\mathopen{{\color{blue}\big(}}#1\mathclose{{\color{blue}\big)}}}


\newcommand*{\TruthTable@ZeroAndOneAsFandT}
{%
      \lccode`~`0 \lccode`F `F \lowercase{\def~{F}}%
      \lccode`~`1 \lccode`T `T \lowercase{\def~{T}}%
%      \catcode`0\active\catcode`1\active
% switch to math active, as anyhow in math mode, 
% and this spares always dangerous \scantokens
      \mathcode`0 "8000 \mathcode`1 "8000
}

% NOW TO OUR \TruthTable MACRO

\newcommand\TruthTable [2]{%
\begingroup\xintverbosetrue % for checking in the log what "stuff" is.
%
% #1 = variables, must be lowercase/uppercase single letters, comma
% separated. Use of T and F forbidden, must be "dummy" letters.
% #2 = comma separated list of expressions. Each expression may have
% (balanced) parentheses and commas, no need to hide the commas in braces.
%
% \fdef is defined in xint, it does less than \edef and is enough here.
%
  \fdef\TruthTable@Vars     {\xintCSVtoList{#1}}%
  \fdef\TruthTable@nbofvars {\xintNthElt{0}{\TruthTable@Vars}}%
  % We are not going to count expressions now, because they are comma
  % separated and possibly the comma is also in use inside as separator
  % for the arguments f the all, any, or xor functions. We could ask
  % the user to brace them, but let's be smarter.
%
   \TruthTableAdjustPrecedences
   \TruthTableParseSyntaxOn
% All the hard work will be done right now
       \xintdeffunc stuff(#1):=nuple(#2);%
   \TruthTableParseSyntaxOff
% Let's now count how many expressions we have:
  \fdef\TruthTable@nbofexprs 
     {\xintNthElt{0}{\xinttheexpr stuff(1..\TruthTable@nbofvars)\relax}}%
% We are now ready for the Table.
  \begin{longtable}
% LONGTABLE PREAMBLE
    {*{\TruthTable@nbofvars}{>{$}c<{$}}|*{\TruthTable@nbofexprs}{>{$}c<{$}}}
% LONGTABLE CAPTION
   \caption {\texttt{\protect\detokenize{#2}}}\\
%
% HEADER ROW WITH FORMATTED EXPRESSIONS (showing precedences with parentheses)
% 
   \xintListWithSep{&}{\TruthTable@Vars}% list of variables
   &%
      \TruthTableFormattingOnWithParens
% The #1 here isn't trimmed of spaces. But we will display in math mode.
      \edef\TruthTable@Formatted {\UseUserFuncMacro{stuff}{#1}}%
      \xintFor ##1 in \TruthTable@Formatted \do 
       {%
   %
   % a complication arise if we want to allow use of T and F in the input
   % syntax, because they have been converted to 1's and 0's. We could demand
   % use of \T and \F, but let's do our (dangerous) \scantokens tricks.
   % Update: I use rather math active characters, as we are in math mode.
   %
   % The "stuff" function will have simplified all things initially like (T
   % \AND T) etc... The only way for this to not happen would be to use \T and
   % \F with some suitable definitions in \TruthTableParseSyntaxOn. But these
   % definitions would depend on inner knowledge of \xintdeffunc/\xintNewExpr
   % functioning.
   %
          \TruthTable@ZeroAndOneAsFandT
          \FixParen ##1\xintifForLast{}{&}%
       }%
   \\
   \hline
%
% THE 2^N EVALUATION ROWS
% We first generate recursively the input truth values
% Later we will use \scantokens tricks to get the commas 
% to act as tabulations. This is faster than parsing them.
% It is not allowed to have ZERO variables ...
  \def\TruthTable@varlist {\do T\do F}%
  \def\do ##1{\noexpand\do {##1,T}\noexpand\do {##1,F}}
  \count@\numexpr\TruthTable@nbofvars\relax
    \xintloop
    \ifnum\count@>\@ne
        \edef\TruthTable@varlist{\TruthTable@varlist}%
        \advance\count@\m@ne
    \repeat
  \let\do\empty
  \edef\TruthTable@varlist{\TruthTable@varlist}%
  \xintFor* ##1 in \TruthTable@varlist \do 
  {%
   % first, the variables for this row. They are a comma separated list.
   % We could use an \xintFor to inserte tabulations, but let's play
   % with catcodes.
      \catcode`, 4 \makeatletter
      \scantokens {\csname @firstofone\endcsname {##1}}% 
       % \scantokens{##1} would not work (exercise...)
      &%
   % second the evaluated expressions.
   % We will obtain a comma separated list of 0's and 1's.
   % We must use \xinttheexpr rather than \UseUserFuncMacro
   % as only inside \xinttheexpr will T and F be interpreted as truth values.
      \fdef\TruthTable@B{\xinttheexpr stuff(##1)\relax}%
   % We now need to convert commas into tabs, could use \xintFor, but well.
      \catcode`, 4 \makeatletter
      \scantokens \expandafter{\expandafter
          \def\expandafter\TruthTable@B\expandafter{\TruthTable@B}%
          }%
% We played some tricks to display the computed 0's and 1's as T's and F's.
% We used at some pointactive characters,
% but it is also possible to do \lowercase.
      \lccode`0 `F \lccode`1 `T
      \lowercase\expandafter{\TruthTable@B}%
   \\%
  }%
  \end{longtable}
\endgroup
}

\makeatother

\begin{document}

% All used variables in second argument must be declared in first argument.

\TruthTable {P, Q}{T, F, P && Q, P||Q, P \XOR T, Q \XOR F}

\TruthTable {P, Q}{P \IMP Q, P \ISIMP Q, P \NIMP Q, P\NISIMP Q, P\IFF Q}

\TruthTable {P,Q}{P 'and' Q, P \AND Q, P\OR Q, P 'or' Q, P\XOR Q, P
  'xor' Q, !(P), not(P)}

\TruthTable {P,Q}{\NOT(P)\OR\NOT(Q), P\IFF Q, P\IMP Q, P\IFF T, Q\IFF F}%

\TruthTable {P,Q}{P\XOR Q, P\AND\NOT(Q)\OR\NOT(P)\AND Q,
                  P\XOR Q \IFF P\AND\NOT(Q)\OR\NOT(P)\AND Q}

\TruthTable {P, Q}{\NOT(P\AND Q)\IFF \NOT(P)\OR\NOT(Q)}

\TruthTable {P,Q}{P\IMP Q, \NOT(Q)\IMP\NOT(P), \NOT(P)\OR Q, \NOT(P\IMP Q), P \AND \NOT(Q)}

\TruthTable {P, Q}{P\IMP Q\IFF \NOT(Q)\IMP \NOT(P)}

\typeout{ICI}\TruthTable {P, Q}{P\IFF Q\IFF (P\IMP Q)\AND(Q\IMP P)}

\TruthTable {P,Q}{P\XOR \NOT(Q)\IFF (P\IFF Q), 
                  P\IMP Q\IFF \NOT (Q)\IMP \NOT(P)}


\TruthTable {P,Q,R}{P\AND Q\AND R, P\OR Q\AND R}

\TruthTable {P,Q,R,S}{xor(P,Q,R,S), (P \XOR Q) \XOR (R \XOR S)}

\TruthTable {P,Q,R}{(P \XOR Q) \XOR R \IFF P \XOR (Q \XOR R)}

\TruthTable {P, Q, R, S}{(P \IMP Q) \AND (Q \IMP R) \AND (R\IMP S) \AND (S \IMP P)\IMP (Q \IFF R)} 

\TruthTable {P, Q, R, S}{(P \OR Q\IMP R)&& (R\IMP S)\IMP (\NOT(S)\IMP\NOT(P))}

\listoftables
\end{document}

输出:

引用

引用

引用

引用

答案4

这是另一个解决方案,它通过对不同变量的 foreach 循环完成并绘制真值表。逻辑函数是根据 pgfmath 的数学函数定义的。该表是用 tikz 绘制的

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{automata,arrows,calc,positioning,fit}

\newcommand{\fffa}[3]{
\pgfmathtruncatemacro{\ffa}{(#1 && #2) ||#3 }
\ffa
}
\begin{document}

\newcommand{\fffb}[3]{
\pgfmathtruncatemacro{\ffb}{#1 &&(#2 ||#3) }
\ffb
}


\begin{tikzpicture}[every node/.style={minimum height=1.5em}]
\node(a){a};
\node[right=2em of a](b){b};
\node[right=2em of b](c){c};
\node[right=2em of c](d){$a\cdot b + c$};
\node[right=2em of d](e){$a \cdot ( b + c)$};
\node[fit =(a) (b) (c) (d) (e)] (l1){};
\draw(l1.south east) --(l1.south west);
\foreach \aa in{0,1}{
    \foreach \bb in{0,1}{
        \foreach \cc in{0,1}{
         \node[below =1em of a](a){\aa};
         \node[below =1em of b](b){\bb};
         \node[below =1em of c](c){\cc};
         \node[below =1em of d](d){\fffa{\aa}{\bb}{\cc}};                
         \node[below =1em of e](e){\fffb{\aa}{\bb}{\cc}};
         \node[fit =(a) (b) (c) (d) (e)] (l2){};
         \draw(l1.east|-l2.south west) -| (l1.north west);
        }
    }
}
\draw (l1.north west) -|(l2.south east-|l1.north east);

\def\lastx{a}
\foreach \nn [remember=\nn as \lastx]in  {b,c,d,e}{
\draw ($0.5*(\lastx)+0.5*(\nn)$) coordinate (xx)  ( xx|-l1.north) -- ( xx|-l2.south) ;
\def\mm{\nn}
}

\end{tikzpicture}


\end{document}

在此处输入图片描述

相关内容