我正在尝试在 LaTeX 中实现格雷码。当前设置有效并输出以下内容(逗号用于视觉区分):
(预期输出:)0,1;00,01,11,10;000, 001, 011, 010, 110, 111,101, 100
格雷码通过将异或运算应用于两个二进制数(我从中获得\int_to_bin:n
并且它们的长度恰好满足需要,因此无需填充)来生成这些序列。
不幸的是,我的\__graycode_xor:nn
函数是不可扩展的,这反过来意味着我无法测量它的长度以在末尾应用一些填充(以使每个位序列同样长)。
我尝试过的方法:将该\graycode_at:n
部分保存到具有不同扩展级别的 tl 变量中,但是没有起作用,因为存在未扩展的部分,导致无法测量长度。
问题:我如何测量不可扩展的东西的长度,以便用零填充其内容?
编辑:我已经对按位运算做了某种填充,这似乎破坏了可扩展性,但我主要关心的是结果(填充放置在输入流中的结果)。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_generate_variant:Nn \int_to_bin:n { V }
% xor on two bits
% #1 and #2: either 0 or 1
\cs_new:Npn \__graycode_xor_bits:nn #1#2
{
\int_compare:nTF { #1 = #2 }
{ 0 } { 1 }
}
% does bitwise xor on two token lists containing binary numbers
% #1 and #2: binary numbers
\cs_new:Npn \__graycode_xor:nn #1#2
{
% set the sequences (of bits) for bitwise operations
\tl_set:Nn \l_tmpa_tl { #1 }
\tl_set:Nn \l_tmpb_tl { #2 }
% compute the padding
\int_set:Nn \l_tmpa_int { \fp_eval:n { abs(\tl_count:N \l_tmpa_tl - \tl_count:N \l_tmpb_tl) } }
\int_compare:nT { \tl_count:N \l_tmpa_tl < \tl_count:N \l_tmpb_tl }
{
% pad \l_tmpa_tl
\prg_replicate:nn { \l_tmpa_int }
{ \tl_put_left:Nn \l_tmpa_tl { 0 } }
}
\int_compare:nT { \tl_count:N \l_tmpb_tl < \tl_count:N \l_tmpa_tl }
{
% pad \l_tmpb_tl
\prg_replicate:nn { \l_tmpa_int }
{ \tl_put_left:Nn \l_tmpb_tl { 0 } }
}
\int_step_inline:nnnn { 1 } { 1 } { \tl_count:N \l_tmpa_tl }
{
\__graycode_xor_bits:nn { \tl_item:Nn \l_tmpa_tl { ##1 } } { \tl_item:Nn \l_tmpb_tl { ##1 } }
}
}
\cs_generate_variant:Nn \__graycode_xor:nn { xx }
% compute the graycode at a specific place
% #1: a decimal number
\cs_new:Npn \graycode_at:n #1
{
\__graycode_xor:xx
{ \int_to_bin:n { #1 - 1 } }
{ \int_to_bin:n { \fp_eval:n { floor((#1-1)/2) } } }
}
% UI for gray code
% #1: 2^n with n in N
\NewDocumentCommand { \graycode } { m }
{
% compute the required number of places (for paddings)
\int_set:Nn \l_tmpa_int { \fp_eval:n { floor(ln(#1)/ln(2)) } }
% generate gray code till current place
\int_step_inline:nnnn { 1 } { 1 } { #1 }
{
% TODO: pad this
\graycode_at:n { ##1 },
}
}
\ExplSyntaxOff
\begin{document}
\graycode{2}\quad
\graycode{4}\quad
\graycode{8}\par
\graycode{16}
\end{document}
答案1
你问如何测量不可膨胀的东西。答案其实就在问题本身:你测量它。
您可以本地选择具有固定宽度数字的字体,并将不可扩展的内容设置为水平框。通过将水平框的宽度除以一个数字的宽度,您可以得到位数。如果您接受以此字体打印结果,您甚至可以使用前导符进行填充:
\documentclass{article}
\usepackage{xparse}
\usepackage{expl3}
\ExplSyntaxOn
\cs_generate_variant:Nn \int_to_bin:n { V }
% xor on two bits
% #1 and #2: either 0 or 1
\cs_new:Npn \__graycode_xor_bits:nn #1#2
{
\int_compare:nTF { #1 = #2 }
{ 0 } { 1 }
}
% does bitwise xor on two token lists containing binary numbers
% #1 and #2: binary numbers
\cs_new:Npn \__graycode_xor:nn #1#2
{
% set the sequences (of bits) for bitwise operations
\tl_set:Nn \l_tmpa_tl { #1 }
\tl_set:Nn \l_tmpb_tl { #2 }
% compute the padding
\int_set:Nn \l_tmpa_int { \fp_eval:n { abs(\tl_count:N \l_tmpa_tl - \tl_count:N \l_tmpb_tl) } }
\int_compare:nT { \tl_count:N \l_tmpa_tl < \tl_count:N \l_tmpb_tl }
{
% pad \l_tmpa_tl
\prg_replicate:nn { \l_tmpa_int }
{ \tl_put_left:Nn \l_tmpa_tl { 0 } }
}
\int_compare:nT { \tl_count:N \l_tmpb_tl < \tl_count:N \l_tmpa_tl }
{
% pad \l_tmpb_tl
\prg_replicate:nn { \l_tmpa_int }
{ \tl_put_left:Nn \l_tmpb_tl { 0 } }
}
\int_step_inline:nnnn { 1 } { 1 } { \tl_count:N \l_tmpa_tl }
{
\__graycode_xor_bits:nn { \tl_item:Nn \l_tmpa_tl { ##1 } } { \tl_item:Nn \l_tmpb_tl { ##1 } }
}
}
\cs_generate_variant:Nn \__graycode_xor:nn { xx }
% compute the graycode at a specific place
% #1: a decimal number
\cs_new:Npn \graycode_at:n #1
{
\__graycode_xor:xx
{ \int_to_bin:n { #1 - 1 } }
{ \int_to_bin:n { \fp_eval:n { floor((#1-1)/2) } } }
}
% UI for gray code
% #1: 2^n with n in N
\NewDocumentCommand { \graycode } { m }
{
\leavevmode
% TODO: Select font with fixed-width numbers
% compute the required number of places (for paddings)
\hbox_set:Nn\l_tmpa_box{\int_to_bin:n{#1-1}}
% generate gray code till current place
\int_step_inline:nnnn { 1 } { 1 } { #1 }
{
\hbox_to_wd:nn{\box_wd:N\l_tmpa_box}{
\leaders\hbox:n{0}\hfil
\graycode_at:n { ##1 }
},
}
}
\ExplSyntaxOff
\begin{document}
\graycode{2}\quad
\graycode{4}\quad
\graycode{8}\par
\graycode{16}
\end{document}
但要解决您的实际问题,在开头添加填充并重写\__graycode_xor:nn
以保持填充完整可能更容易。例如:
\documentclass{article}
\usepackage{expl3,xparse}
\ExplSyntaxOn
% xor on two bits
% #1 and #2: either 0 or 1
\cs_new:Npn \__graycode_xor_bits:nn #1#2
{
\int_compare:nNnTF{#1}={#2}
{ 0 } { 1 }
}
\cs_new:Npn\__graycode_xor:w#1#2\q_stop#3#4\q_stop{
\__graycode_xor_bits:nn{#1}{#3}
\tl_if_empty:nF{#2}{
\__graycode_xor:w#2\q_stop#4\q_stop
}
}
\cs_new:Nn\__graycode_xor:nn{
\__graycode_xor:w#1\q_stop#2\q_stop
}
\cs_generate_variant:Nn\__graycode_xor:nn{ff}
\cs_new:Nn\graycode_at:nn{
\__graycode_xor:ff
{ \tl_tail:f{\int_to_bin:n { #1 - 1 + #2 } } }
{ \tl_tail:f{\int_to_bin:n { \fp_eval:n { floor((#1-1)/2) + #2 } } } }
}
\NewDocumentCommand { \graycode } { m }
{
% generate gray code till current place
\int_step_inline:nnnn { 1 } { 1 } { #1 }
{
\graycode_at:nn { ##1 }{ #1 },
}
}
\ExplSyntaxOff
\begin{document}
\graycode{2}\quad
\graycode{4}\quad
\graycode{8}\par
\graycode{16}
\end{document}
编辑:此实现\__graycode_xor:nn
基于递归:通过将参数传递给\__graycode_xor:w
分离出的第一个数字。然后计算第一个数字(#1
和#3
)的按位异或。如果#2
第一个参数的剩余部分不为空,则还有其他位要进行异或,因此我们递归调用宏来计算尾部。这假设参数具有相同的长度,但对于此算法而言,这始终是正确的,因为在开头添加了填充。