我需要为我的计算机架构课程输入真值表。到目前为止,我一直在使用手动输入,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
兼容性更新
release
1.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
,通过对整数进行二进制扩展0
,1
...最多为2^n-1
,n
变量数量。这使得编码更紧凑(效率也更低,但这并不重要)。
第二个答案另外添加了一个可选参数,允许用户直接指定表达式在标题行中的显示方式。
此外,它也允许最后的表达式以 结尾;
。
而且,星号变体使用\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
可能最多有9
;5
字母已经有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
我提供另一个答案有两个原因:
自 2015 年秋季起,
xint
可以发布一种更简单的方法;不需要激活字母来扫描变量。这种更简单的方法也更强大:不需要使用
\AND
、\OR
等宏来格式化输入;它可以在理解的语法中给出\xintexpr
。然后就可以用合适的符号来评估和格式化原始表达式。在对第一个答案的评论中,有人问如何添加更多运算符。无法处理语法中未知的二进制中缀逻辑运算符
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}