LaTeX3 填充一些不可扩展的东西

LaTeX3 填充一些不可扩展的东西

我正在尝试在 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第一个参数的剩余部分不为空,则还有其他位要进行异或,因此我们递归调用宏来计算尾部。这假设参数具有相同的长度,但对于此算法而言,这始终是正确的,因为在开头添加了填充。

相关内容