1

The code below try to implement the Eratosthenes' sieve, but the boolean tests fail: in the M(not)WE below, max integer is 4 so integers greater than 4 should be ignored. What am I missing?

enter image description here

\documentclass{article}

\ExplSyntaxOn

\int_new:N \l_row_int \int_new:N \l_col_int

\NewDocumentCommand\eratosthenes{ O{#2}m }{
\seq_new:N \l_notprime_seq

\int_new:N  \l_tested_int
\int_set:Nn \l_tested_int { 1 }

\int_new:N  \l_striked_int

\int_new:N  \l_max_int
\int_set:Nn \l_max_int { #2*#2 }

\int_do_while:nn {

% \l_tested_int <= #2 % The following inefficient test shows one of my problem. \l_tested_int <= \l_max_int } { \int_compare:nNnTF \l_tested_int = 1 { STRIKE ~ ME: ~ 1 \seq_put_left:Nn \l_notprime_seq 1 } { \seq_if_in:NnF \l_notprime_seq \l_tested_int { \int_set:Nn \l_striked_int { 2*\l_tested_int }

            \int_do_while:nn {
                \l_striked_int &lt;= \l_max_int
            } {

% \seq_if_in:NnF \l_notprime_seq \l_striked_int { \ STRIKE ~ ME: ~ \int_use:N \l_striked_int \seq_put_left:Nn \l_notprime_seq {\l_striked_int} % }

                \int_set:Nn \l_striked_int { \l_striked_int + \l_tested_int }         
            }
        }
    }

    \int_incr:N \l_tested_int

% \int_show:N \l_tested_int % \int_show:N \l_max_int

% \seq_show:N \l_notprime_seq } }

\ExplSyntaxOff

\begin{document}

\eratosthenes{2}

\end{document}

User23456234
  • 1,808
projetmbc
  • 13,315
  • 1
    plant \int_show:N everywhere to check the logic. And correct the naming of your variables, it should be \l_my_max_int and \l_my_striked_int. – Ulrike Fischer Jun 12 '23 at 13:44
  • 1
    Renaming done. I'm going to start gardening. – projetmbc Jun 12 '23 at 13:50
  • 1
    If the only check per \bool_if:nTF you need is one \int_compare_p:n, don't use \bool_if:nTF, but instead \int_compare:nNnTF or \int_compare:nTF (the former if you don't need <= but only <, it is much faster). – Skillmon Jun 12 '23 at 14:13
  • Such a shame... My problem is indeed with \bool_do_while:nn { \int_compare_p:n {\l_striked_int <= \l_max_int } }. – projetmbc Jun 12 '23 at 14:19
  • I have missed things like int_do_while. I will play with this now... – projetmbc Jun 12 '23 at 14:20
  • @Skillmon I have tried to use the INT primitives, but the problem does not seem to be solved. – projetmbc Jun 12 '23 at 14:31
  • @UlrikeFischer may complain my l3 code is not fully idiomatic https://tex.stackexchange.com/a/134320/1090 – David Carlisle Jun 12 '23 at 14:55
  • In fact I got confused with do_while and while_do. I'll be inoculated in future. I'll answer my question in a few minutes... – projetmbc Jun 12 '23 at 15:10
  • Does it make sense to have do_while and do_until ? There are synonyms in a sense. do_while PREDICATE <===> do_until NOT PREDICATE. No? – projetmbc Jun 12 '23 at 15:26
  • That was not about a problem, they'll do the same, \bool_if:nTF is just much slower if you only use it on a single predicate. – Skillmon Jun 12 '23 at 18:20
  • OK. So this can be useful with predicates like a < b to obtain quickly do_until a >= b via do_while a < b. This should be indicated clearly in the interface3 PDF. – projetmbc Jun 12 '23 at 23:05

1 Answers1

2

Here is a basic solution for the loops. \int_while_do must be used instead of \int_do_while. It remains to make efficient the use of the sequence of integers that does not work here, even if this gives a correct "visual" algorithm. SEe below for a solution.

\documentclass{article}

\ExplSyntaxOn

\int_new:N \l_row_int \int_new:N \l_col_int

\NewDocumentCommand\eratosthenes{ O{#2}m }{
\seq_new:N \l_notprime_seq

\int_new:N  \l_tested_int
\int_set:Nn \l_tested_int { 1 }

\int_new:N  \l_striked_int

\int_new:N  \l_max_int
\int_set:Nn \l_max_int { #2*#2 }

\int_while_do:nn {

% \l_tested_int <= #2 % The following inefficient test shows one of my problem. \l_tested_int <= \l_max_int } { \int_compare:nNnTF \l_tested_int = 1 { \ \quad STRIKE ~ THIS: ~ 1 \seq_put_left:Nn \l_notprime_seq 1 } { \seq_if_in:NnTF \l_notprime_seq \l_tested_int { \ PRIME: ~ \int_use:N \l_tested_int } { \int_set:Nn \l_striked_int { 2*\l_tested_int }

            \int_while_do:nn {
                \l_striked_int &lt;= \l_max_int
            } {

% \seq_if_in:NnF \l_notprime_seq \l_striked_int { \ \quad STRIKE ~ ME: ~ \int_use:N \l_striked_int \seq_put_left:Nn \l_notprime_seq {\l_striked_int} % }

                \int_set:Nn \l_striked_int { \l_striked_int + \l_tested_int }         
            }
        }
    }

    \int_incr:N \l_tested_int
}

}

\ExplSyntaxOff

\begin{document}

\noindent \eratosthenes{3}

\end{document}

This code correctly prints.

STRIKE THIS: 1
STRIKE ME: 4 
STRIKE ME: 6 
STRIKE ME: 8 
STRIKE ME: 6 
STRIKE ME: 9 
STRIKE ME: 8

Final version striking numbers only once

Here is the code I was looking for. This makes an interesting LaTeX3 exercise.

enter image description here

\documentclass{article}

\usepackage{nicematrix} \usepackage{tikz}

\NewDocumentCommand\drawstrike{ mm } {
\begin{tikzpicture}[ remember picture, overlay ] \draw[ very thick, red, opacity = 0.3 ] ([xshift=-3pt]this-#1-#2.north west) -- ([xshift=3pt]this-#1-#2.south east); \end{tikzpicture} }

\ExplSyntaxOn

\int_new:N \l_row_int \int_new:N \l_col_int

\NewDocumentCommand\strikeme{ mm } { \int_set:Nn \l_row_int { \int_div_truncate:nn {#2}{#1} } \int_set:Nn \l_col_int { \int_mod:nn {#2} {#1}}

\int_compare:nNnTF \l_col_int = 0 {
    \int_set:Nn \l_col_int { #1 }
} {
    \int_set:Nn \l_row_int { \l_row_int + 1}
}

\drawstrike{\int_use:N \l_row_int}{\int_use:N \l_col_int}

}

\NewDocumentCommand\eratosthenes{ O{#2}m }{
$\AutoNiceMatrix[ hvlines, columns - width = auto, name = this ]{ #2-#2 }{ \cellval{#2}{\arabic{iRow}}{\arabic{jCol}} }$

\seq_new:N \l_notprime_seq

\int_new:N  \l_tested_int
\int_set:Nn \l_tested_int { 1 }

\int_new:N  \l_striked_int

\int_new:N  \l_max_int
\int_set:Nn \l_max_int { #2*#2 }

\int_while_do:nn {
     \l_tested_int &lt;= #2
} {
    \int_compare:nNnTF \l_tested_int = 1 {
        \strikeme{#2}{1}
        \seq_put_left:Nn \l_notprime_seq 1
    } {
        \seq_if_in:NxF \l_notprime_seq {\int_use:N \l_tested_int} {
            \int_set:Nn \l_striked_int { 2*\l_tested_int }

            \int_while_do:nn {
                \l_striked_int &lt;= \l_max_int
            } {
                \seq_if_in:NxF \l_notprime_seq {\int_use:N \l_striked_int} {
                    \strikeme{#2}{\int_use:N \l_striked_int}
                    \seq_put_left:Nx \l_notprime_seq {\int_use:N \l_striked_int}
                }

                \int_set:Nn \l_striked_int { \l_striked_int + \l_tested_int }         
            }
        }
    }

    \int_incr:N \l_tested_int
}

}

\NewDocumentCommand\cellval{ mmm }{
\int_eval:n{#3 + #1*(#2 - 1)} }

\ExplSyntaxOff

\begin{document}

\eratosthenes{10}

\end{document}

projetmbc
  • 13,315