From 507fa9c669d7e4bc2c808f269113c6ced0b18827 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Sat, 6 May 2023 03:01:13 +0000 Subject: CTAN sync 202305060301 --- macros/latex/contrib/l3kernel/l3fp-random.dtx | 527 ++++++++++++-------------- 1 file changed, 245 insertions(+), 282 deletions(-) (limited to 'macros/latex/contrib/l3kernel/l3fp-random.dtx') diff --git a/macros/latex/contrib/l3kernel/l3fp-random.dtx b/macros/latex/contrib/l3kernel/l3fp-random.dtx index ba0a9a8e23..94313834ba 100644 --- a/macros/latex/contrib/l3kernel/l3fp-random.dtx +++ b/macros/latex/contrib/l3kernel/l3fp-random.dtx @@ -40,7 +40,7 @@ % {latex-team@latex-project.org}^^A % }^^A % } -% \date{Released 2023-04-20} +% \date{Released 2023-05-05} % % \maketitle % @@ -73,37 +73,6 @@ % % \subsection{Engine support} % -% Most engines provide random numbers, but not all. We write the test -% twice simply in order to write the \texttt{false} branch first. -% \begin{macrocode} -\sys_if_rand_exist:F - { - \msg_new:nnn { kernel } { fp-no-random } - { Random~numbers~unavailable~for~#1 } - \cs_new:Npn \@@_rand_o:Nw ? #1 @ - { - \msg_expandable_error:nnn { kernel } { fp-no-random } - { fp~rand } - \exp_after:wN \c_nan_fp - } - \cs_new_eq:NN \@@_randint_o:Nw \@@_rand_o:Nw - \cs_new:Npn \int_rand:nn #1#2 - { - \msg_expandable_error:nnn { kernel } { fp-no-random } - { \int_rand:nn {#1} {#2} } - \int_eval:n {#1} - } - \cs_new:Npn \int_rand:n #1 - { - \msg_expandable_error:nnn { kernel } { fp-no-random } - { \int_rand:n {#1} } - 1 - } - } -\sys_if_rand_exist:T - { -% \end{macrocode} -% % Obviously, every word \enquote{random} below means % \enquote{pseudo-random}, as we have no access to entropy (except a % very unreliable source of entropy: the time it takes to run some @@ -271,7 +240,7 @@ % Constant equal to $2^{17}-1$, the maximal size of a range that % \cs{int_range:nn} can do with its \enquote{simple} algorithm. % \begin{macrocode} - \int_const:Nn \c__kernel_randint_max_int { 131071 } +\int_const:Nn \c__kernel_randint_max_int { 131071 } % \end{macrocode} % \end{variable} % @@ -284,11 +253,11 @@ % $\operatorname{ediv}(p-2^{13},2^{14})$ but that wrongly gives $-1$ % for $p=0$. % \begin{macrocode} - \cs_new:Npn \__kernel_randint:n #1 - { - (#1 * \tex_uniformdeviate:D 16384 - + \tex_uniformdeviate:D #1 + 8192 ) / 16384 - } +\cs_new:Npn \__kernel_randint:n #1 + { + (#1 * \tex_uniformdeviate:D 16384 + + \tex_uniformdeviate:D #1 + 8192 ) / 16384 + } % \end{macrocode} % \end{macro} % @@ -300,17 +269,17 @@ % four (pseudo-random) digits. Digits are produced as a random number % in $[10000,19999]$ for the usual reason of preserving leading zeros. % \begin{macrocode} - \cs_new:Npn \@@_rand_myriads:n #1 - { \@@_rand_myriads_loop:w #1 \prg_break: X \prg_break_point: ; } - \cs_new:Npn \@@_rand_myriads_loop:w #1 X - { - #1 - \exp_after:wN \@@_rand_myriads_get:w - \int_value:w \@@_int_eval:w 9999 + - \__kernel_randint:n { 10000 } - \@@_rand_myriads_loop:w - } - \cs_new:Npn \@@_rand_myriads_get:w 1 #1 ; { ; {#1} } +\cs_new:Npn \@@_rand_myriads:n #1 + { \@@_rand_myriads_loop:w #1 \prg_break: X \prg_break_point: ; } +\cs_new:Npn \@@_rand_myriads_loop:w #1 X + { + #1 + \exp_after:wN \@@_rand_myriads_get:w + \int_value:w \@@_int_eval:w 9999 + + \__kernel_randint:n { 10000 } + \@@_rand_myriads_loop:w + } +\cs_new:Npn \@@_rand_myriads_get:w 1 #1 ; { ; {#1} } % \end{macrocode} % \end{macro} % @@ -324,27 +293,27 @@ % is correctly~$0$ but it raises the \texttt{underflow} flag; it % should not do that. % \begin{macrocode} - \cs_new:Npn \@@_rand_o:Nw ? #1 @ +\cs_new:Npn \@@_rand_o:Nw ? #1 @ + { + \tl_if_empty:nTF {#1} { - \tl_if_empty:nTF {#1} - { - \exp_after:wN \@@_rand_o:w - \exp:w \exp_end_continue_f:w - \@@_rand_myriads:n { XXXX } { 0000 } { 0000 } ; 0 - } - { - \msg_expandable_error:nnnnn - { fp } { num-args } { rand() } { 0 } { 0 } - \exp_after:wN \c_nan_fp - } + \exp_after:wN \@@_rand_o:w + \exp:w \exp_end_continue_f:w + \@@_rand_myriads:n { XXXX } { 0000 } { 0000 } ; 0 } - \cs_new:Npn \@@_rand_o:w ; { - \exp_after:wN \@@_sanitize:Nw - \exp_after:wN 0 - \int_value:w \@@_int_eval:w \c_zero_int - \@@_fixed_to_float_o:wN + \msg_expandable_error:nnnnn + { fp } { num-args } { rand() } { 0 } { 0 } + \exp_after:wN \c_nan_fp } + } +\cs_new:Npn \@@_rand_o:w ; + { + \exp_after:wN \@@_sanitize:Nw + \exp_after:wN 0 + \int_value:w \@@_int_eval:w \c_zero_int + \@@_fixed_to_float_o:wN + } % \end{macrocode} % \end{macro} % @@ -382,115 +351,115 @@ % numbers (namely $10^{16}$ to the integers they represent), except % of course when it is time to convert back to a float. % \begin{macrocode} - \cs_new:Npn \@@_randint_o:Nw ? - { - \@@_parse_function_one_two:nnw - { randint } - { \@@_randint_default:w \@@_randint_o:w } - } - \cs_new:Npn \@@_randint_default:w #1 { \exp_after:wN #1 \c_one_fp } - \cs_new:Npn \@@_randint_badarg:w \s_@@ \@@_chk:w #1#2#3; - { - \@@_int:wTF \s_@@ \@@_chk:w #1#2#3; - { - \if_meaning:w 1 #1 - \if_int_compare:w - \@@_use_i_until_s:nw #3 ; > \c_@@_prec_int - \c_one_int - \fi: - \fi: - } - { \c_one_int } - } - \cs_new:Npn \@@_randint_o:w #1; #2; @ - { - \if_case:w - \@@_randint_badarg:w #1; - \@@_randint_badarg:w #2; - \if:w 1 \@@_compare_back:ww #2; #1; \c_one_int \fi: - \c_zero_int - \@@_randint_auxi_o:ww #1; #2; - \or: - \@@_invalid_operation_tl_o:ff - { randint } { \@@_array_to_clist:n { #1; #2; } } - \exp:w - \fi: - \exp_after:wN \exp_end: - } - \cs_new:Npn \@@_randint_auxi_o:ww #1 ; #2 ; #3 \exp_end: - { - \fi: - \@@_randint_auxii:wn #2 ; - { \@@_randint_auxii:wn #1 ; \@@_randint_auxiii_o:ww } - } - \cs_new:Npn \@@_randint_auxii:wn \s_@@ \@@_chk:w #1#2#3#4 ; - { - \if_meaning:w 0 #1 - \exp_after:wN \use_i:nn - \else: - \exp_after:wN \use_ii:nn - \fi: - { \exp_after:wN \@@_fixed_continue:wn \c_@@_one_fixed_tl } - { - \exp_after:wN \@@_ep_to_fixed:wwn - \int_value:w \@@_int_eval:w - #3 - \c_@@_prec_int , #4 {0000} {0000} ; - { - \if_meaning:w 0 #2 - \exp_after:wN \use_i:nnnn - \exp_after:wN \@@_fixed_add_one:wN - \fi: - \exp_after:wN \@@_fixed_sub:wwn \c_@@_one_fixed_tl - } - \@@_fixed_continue:wn - } - } - \cs_new:Npn \@@_randint_auxiii_o:ww #1 ; #2 ; - { - \@@_fixed_add:wwn #2 ; - {0000} {0000} {0000} {0001} {0000} {0000} ; - \@@_fixed_sub:wwn #1 ; - { - \exp_after:wN \use_i:nn - \exp_after:wN \@@_fixed_mul_add:wwwn - \exp:w \exp_end_continue_f:w \@@_rand_myriads:n { XXXXXX } ; - } - #1 ; - \@@_randint_auxiv_o:ww - #2 ; - \@@_randint_auxv_o:w #1 ; @ - } - \cs_new:Npn \@@_randint_auxiv_o:ww #1#2#3#4#5 ; #6#7#8#9 +\cs_new:Npn \@@_randint_o:Nw ? + { + \@@_parse_function_one_two:nnw + { randint } + { \@@_randint_default:w \@@_randint_o:w } + } +\cs_new:Npn \@@_randint_default:w #1 { \exp_after:wN #1 \c_one_fp } +\cs_new:Npn \@@_randint_badarg:w \s_@@ \@@_chk:w #1#2#3; + { + \@@_int:wTF \s_@@ \@@_chk:w #1#2#3; { - \if_int_compare:w - \if_int_compare:w #1#2 > #6#7 \exp_stop_f: 1 \else: - \if_int_compare:w #1#2 < #6#7 \exp_stop_f: - \fi: \fi: - #3#4 > #8#9 \exp_stop_f: - \@@_use_i_until_s:nw + \if_meaning:w 1 #1 + \if_int_compare:w + \@@_use_i_until_s:nw #3 ; > \c_@@_prec_int + \c_one_int + \fi: \fi: - \@@_randint_auxv_o:w {#1}{#2}{#3}{#4}#5 } - \cs_new:Npn \@@_randint_auxv_o:w #1#2#3#4#5 ; #6 @ + { \c_one_int } + } +\cs_new:Npn \@@_randint_o:w #1; #2; @ + { + \if_case:w + \@@_randint_badarg:w #1; + \@@_randint_badarg:w #2; + \if:w 1 \@@_compare_back:ww #2; #1; \c_one_int \fi: + \c_zero_int + \@@_randint_auxi_o:ww #1; #2; + \or: + \@@_invalid_operation_tl_o:ff + { randint } { \@@_array_to_clist:n { #1; #2; } } + \exp:w + \fi: + \exp_after:wN \exp_end: + } +\cs_new:Npn \@@_randint_auxi_o:ww #1 ; #2 ; #3 \exp_end: + { + \fi: + \@@_randint_auxii:wn #2 ; + { \@@_randint_auxii:wn #1 ; \@@_randint_auxiii_o:ww } + } +\cs_new:Npn \@@_randint_auxii:wn \s_@@ \@@_chk:w #1#2#3#4 ; + { + \if_meaning:w 0 #1 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { \exp_after:wN \@@_fixed_continue:wn \c_@@_one_fixed_tl } + { + \exp_after:wN \@@_ep_to_fixed:wwn + \int_value:w \@@_int_eval:w + #3 - \c_@@_prec_int , #4 {0000} {0000} ; { - \exp_after:wN \@@_sanitize:Nw - \int_value:w - \if_int_compare:w #1 < 10000 \exp_stop_f: - 2 - \else: - 0 - \exp_after:wN \exp_after:wN - \exp_after:wN \@@_reverse_args:Nww + \if_meaning:w 0 #2 + \exp_after:wN \use_i:nnnn + \exp_after:wN \@@_fixed_add_one:wN \fi: \exp_after:wN \@@_fixed_sub:wwn \c_@@_one_fixed_tl - {#1} {#2} {#3} {#4} {0000} {0000} ; - { - \exp_after:wN \exp_stop_f: - \int_value:w \@@_int_eval:w \c_@@_prec_int - \@@_fixed_to_float_o:wN - } - 0 - \exp:w \exp_after:wN \exp_end: } + \@@_fixed_continue:wn + } + } +\cs_new:Npn \@@_randint_auxiii_o:ww #1 ; #2 ; + { + \@@_fixed_add:wwn #2 ; + {0000} {0000} {0000} {0001} {0000} {0000} ; + \@@_fixed_sub:wwn #1 ; + { + \exp_after:wN \use_i:nn + \exp_after:wN \@@_fixed_mul_add:wwwn + \exp:w \exp_end_continue_f:w \@@_rand_myriads:n { XXXXXX } ; + } + #1 ; + \@@_randint_auxiv_o:ww + #2 ; + \@@_randint_auxv_o:w #1 ; @ + } +\cs_new:Npn \@@_randint_auxiv_o:ww #1#2#3#4#5 ; #6#7#8#9 + { + \if_int_compare:w + \if_int_compare:w #1#2 > #6#7 \exp_stop_f: 1 \else: + \if_int_compare:w #1#2 < #6#7 \exp_stop_f: - \fi: \fi: + #3#4 > #8#9 \exp_stop_f: + \@@_use_i_until_s:nw + \fi: + \@@_randint_auxv_o:w {#1}{#2}{#3}{#4}#5 + } +\cs_new:Npn \@@_randint_auxv_o:w #1#2#3#4#5 ; #6 @ + { + \exp_after:wN \@@_sanitize:Nw + \int_value:w + \if_int_compare:w #1 < 10000 \exp_stop_f: + 2 + \else: + 0 + \exp_after:wN \exp_after:wN + \exp_after:wN \@@_reverse_args:Nww + \fi: + \exp_after:wN \@@_fixed_sub:wwn \c_@@_one_fixed_tl + {#1} {#2} {#3} {#4} {0000} {0000} ; + { + \exp_after:wN \exp_stop_f: + \int_value:w \@@_int_eval:w \c_@@_prec_int + \@@_fixed_to_float_o:wN + } + 0 + \exp:w \exp_after:wN \exp_end: + } % \end{macrocode} % \end{macro} % \end{macro} @@ -504,38 +473,38 @@ % where \meta{choices} is the number of possible outcomes. If the % range is wide, use somewhat slower code. % \begin{macrocode} - \cs_new:Npn \int_rand:nn #1#2 +\cs_new:Npn \int_rand:nn #1#2 + { + \int_eval:n { - \int_eval:n - { - \exp_after:wN \@@_randint:ww - \int_value:w \int_eval:n {#1} \exp_after:wN ; - \int_value:w \int_eval:n {#2} ; - } + \exp_after:wN \@@_randint:ww + \int_value:w \int_eval:n {#1} \exp_after:wN ; + \int_value:w \int_eval:n {#2} ; } - \cs_new:Npn \@@_randint:ww #1; #2; - { - \if_int_compare:w #1 > #2 \exp_stop_f: - \msg_expandable_error:nnnn - { kernel } { randint-backward-range } {#1} {#2} - \@@_randint:ww #2; #1; - \else: - \if_int_compare:w \@@_int_eval:w #2 - \if_int_compare:w #1 > \c_zero_int - - #1 < \@@_int_eval:w - \else: - < \@@_int_eval:w #1 + - \fi: - \c__kernel_randint_max_int - \@@_int_eval_end: - \__kernel_randint:n - { \@@_int_eval:w #2 - #1 + 1 \@@_int_eval_end: } - - 1 + #1 + } +\cs_new:Npn \@@_randint:ww #1; #2; + { + \if_int_compare:w #1 > #2 \exp_stop_f: + \msg_expandable_error:nnnn + { kernel } { randint-backward-range } {#1} {#2} + \@@_randint:ww #2; #1; + \else: + \if_int_compare:w \@@_int_eval:w #2 + \if_int_compare:w #1 > \c_zero_int + - #1 < \@@_int_eval:w \else: - \__kernel_randint:nn {#1} {#2} + < \@@_int_eval:w #1 + \fi: - \fi: - } + \c__kernel_randint_max_int + \@@_int_eval_end: + \__kernel_randint:n + { \@@_int_eval:w #2 - #1 + 1 \@@_int_eval_end: } + - 1 + #1 + \else: + \__kernel_randint:nn {#1} {#2} + \fi: + \fi: + } % \end{macrocode} % \end{macro} % @@ -557,101 +526,95 @@ % \meta{Y_1}|;|\meta{Y_0}|;| \meta{R_2}|;|\meta{R_1}|;|\meta{R_0}|;.| % and we apply the algorithm described earlier. % \begin{macrocode} - \cs_new:Npn \__kernel_randint:nn #1#2 - { - #1 - \exp_after:wN \@@_randint_wide_aux:w - \int_value:w - \exp_after:wN \@@_randint_split_o:Nw - \tex_uniformdeviate:D 268435456 ; - \int_value:w - \exp_after:wN \@@_randint_split_o:Nw - \tex_uniformdeviate:D 268435456 ; +\cs_new:Npn \__kernel_randint:nn #1#2 + { + #1 + \exp_after:wN \@@_randint_wide_aux:w + \int_value:w + \exp_after:wN \@@_randint_split_o:Nw + \tex_uniformdeviate:D 268435456 ; + \int_value:w + \exp_after:wN \@@_randint_split_o:Nw + \tex_uniformdeviate:D 268435456 ; + \int_value:w + \exp_after:wN \@@_randint_split_o:Nw + \int_value:w \@@_int_eval:w 131072 + + \exp_after:wN \@@_randint_split_o:Nw \int_value:w - \exp_after:wN \@@_randint_split_o:Nw - \int_value:w \@@_int_eval:w 131072 + - \exp_after:wN \@@_randint_split_o:Nw - \int_value:w - \__kernel_int_add:nnn {#2} { -#1 } { -\c_max_int } ; - . - } - \cs_new:Npn \@@_randint_split_o:Nw #1#2 ; - { - \if_meaning:w 0 #1 - 0 \exp_after:wN ; \int_value:w 0 - \else: - \exp_after:wN \@@_randint_split_aux:w - \int_value:w \@@_int_eval:w (#1#2 - 8192) / 16384 ; - + #1#2 - \fi: - \exp_after:wN ; - } - \cs_new:Npn \@@_randint_split_aux:w #1 ; - { - #1 \exp_after:wN ; - \int_value:w \@@_int_eval:w - #1 * 16384 - } - \cs_new:Npn \@@_randint_wide_aux:w #1;#2; #3;#4; #5;#6;#7; . - { - \exp_after:wN \@@_randint_wide_auxii:w - \int_value:w \@@_int_eval:w #5 * #3 + #6 * #1 + - (#5 * #4 + #6 * #3 + #7 * #1 + - (#5 * #2 + #7 * #3 + - (16384 * #6 + #7) * (16384 * #4 + #2) / 268435456) / 16384 - ) / 16384 \exp_after:wN ; - \int_value:w \@@_int_eval:w (#5 + #6) * 16384 + #7 ; - #1 ; #5 ; - } - \cs_new:Npn \@@_randint_wide_auxii:w #1; #2; #3; #4; - { - \if_int_odd:w 0 - \if_int_compare:w #1 = #2 \else: \exp_stop_f: \fi: - \if_int_compare:w #4 = \c_zero_int 1 \fi: - \if_int_compare:w #3 = 16383 ~ 1 \fi: - \exp_stop_f: - \exp_after:wN \prg_break: - \fi: - \if_int_compare:w #4 < 8 \exp_stop_f: - + #4 * #3 * 16384 - \else: - + 8 * #3 * 16384 + (#4 - 8) * #3 * 16384 - \fi: - + #1 - \prg_break_point: - } + \__kernel_int_add:nnn {#2} { -#1 } { -\c_max_int } ; + . + } +\cs_new:Npn \@@_randint_split_o:Nw #1#2 ; + { + \if_meaning:w 0 #1 + 0 \exp_after:wN ; \int_value:w 0 + \else: + \exp_after:wN \@@_randint_split_aux:w + \int_value:w \@@_int_eval:w (#1#2 - 8192) / 16384 ; + + #1#2 + \fi: + \exp_after:wN ; + } +\cs_new:Npn \@@_randint_split_aux:w #1 ; + { + #1 \exp_after:wN ; + \int_value:w \@@_int_eval:w - #1 * 16384 + } +\cs_new:Npn \@@_randint_wide_aux:w #1;#2; #3;#4; #5;#6;#7; . + { + \exp_after:wN \@@_randint_wide_auxii:w + \int_value:w \@@_int_eval:w #5 * #3 + #6 * #1 + + (#5 * #4 + #6 * #3 + #7 * #1 + + (#5 * #2 + #7 * #3 + + (16384 * #6 + #7) * (16384 * #4 + #2) / 268435456) / 16384 + ) / 16384 \exp_after:wN ; + \int_value:w \@@_int_eval:w (#5 + #6) * 16384 + #7 ; + #1 ; #5 ; + } +\cs_new:Npn \@@_randint_wide_auxii:w #1; #2; #3; #4; + { + \if_int_odd:w 0 + \if_int_compare:w #1 = #2 \else: \exp_stop_f: \fi: + \if_int_compare:w #4 = \c_zero_int 1 \fi: + \if_int_compare:w #3 = 16383 ~ 1 \fi: + \exp_stop_f: + \exp_after:wN \prg_break: + \fi: + \if_int_compare:w #4 < 8 \exp_stop_f: + + #4 * #3 * 16384 + \else: + + 8 * #3 * 16384 + (#4 - 8) * #3 * 16384 + \fi: + + #1 + \prg_break_point: + } % \end{macrocode} % \end{macro} % % \begin{macro}{\int_rand:n, \@@_randint:n} % Similar to \cs{int_rand:nn}, but needs fewer checks. % \begin{macrocode} - \cs_new:Npn \int_rand:n #1 - { - \int_eval:n - { \exp_args:Nf \@@_randint:n { \int_eval:n {#1} } } - } - \cs_new:Npn \@@_randint:n #1 - { - \if_int_compare:w #1 < \c_one_int - \msg_expandable_error:nnnn - { kernel } { randint-backward-range } { 1 } {#1} - \@@_randint:ww #1; 1; - \else: - \if_int_compare:w #1 > \c__kernel_randint_max_int - \__kernel_randint:nn { 1 } {#1} - \else: - \__kernel_randint:n {#1} - \fi: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% End the initial conditional that ensures these commands are only -% defined in engines that support random numbers. -% \begin{macrocode} +\cs_new:Npn \int_rand:n #1 + { + \int_eval:n + { \exp_args:Nf \@@_randint:n { \int_eval:n {#1} } } + } +\cs_new:Npn \@@_randint:n #1 + { + \if_int_compare:w #1 < \c_one_int + \msg_expandable_error:nnnn + { kernel } { randint-backward-range } { 1 } {#1} + \@@_randint:ww #1; 1; + \else: + \if_int_compare:w #1 > \c__kernel_randint_max_int + \__kernel_randint:nn { 1 } {#1} + \else: + \__kernel_randint:n {#1} + \fi: + \fi: } % \end{macrocode} +% \end{macro} % % \begin{macrocode} % -- cgit v1.2.3