Este team redactor ha estado mucho tiempo buscando para darle espuestas a tus dudas, te ofrecemos la solución por eso nuestro objetivo es resultarte de mucha apoyo.
Solución:
Puedes usar fp_eval:n
y rand()
de expl3
. Según interface3.pdf, rand()
produce un número de punto flotante pseudoaleatorio (en realidad, un múltiplo de 10-dieciséis) entre 0 incluido y 1 excluido.
Primera interpretación de la pregunta (randA
)
Con una pequeña transformación afín, podemos transformar el [0, 1) range into what you seem to want: [3/4*(#1), 5/4*(#1)) [see note 1]. Entonces podemos usar round()
para redondear el resultado intermedio al número entero más cercano. El resultado final es un número entero en el [8, 12] rango cuando #1
es 10.
Aquí, usé intencionalmente rand()
en lugar de randint()
debido al comentario de su ejemplo, “esto debería devolver 1 número entre 7.5-12.5, idealmente redondeado”. De hecho, adaptando el método a, por ejemplo, el rango [7.2, 10.1], no daría los mismos resultados que para, por ejemplo, el rango [7.4, 10.1]: los mismos valores enteros del rango [7, 10] podría obtenerse en ambos casos, pero no con las mismas frecuencias. Me parece que esto es lo que quieres, dado el comentario de tu ejemplo.
Tenga en cuenta que este algoritmo no produce todos los valores enteros posibles con la misma probabilidad (pero consulte el randB
variante a continuación). Por ejemplo, si randA
se llama con el argumento 12
, el rango flotante calculado es [9, 15) because 3(/4)*12 = 9 and (5/4)*12 = 15, and the random uniform choice happens in this range. Let’s call y the result of this random uniform choice. The final result (full expansion of randA12
) is:
-
9 if y is in [9, 9.5)
-
10 if y is in [9.5, 10.5]
-
11 si y está en (10.5, 11.5)
-
12 si y es en [11.5, 12.5]
-
13 si y está en (12,5, 13,5)
-
14 si y es en [13.5, 14.5]
-
15 si y está en (14.5, 15).
Todos estos intervalos tienen una longitud de 1, excepto el primero y el último, que tienen una longitud de 0,5. Por lo tanto, si descuidamos el hecho de que el número de posibles valores de retorno de rand()
es finito y que algunos de los extremos del intervalo están abiertos y otros están cerrados, randa12
devuelve uno de 10, 11, 12, 13, 14 con una probabilidad de 1/6 y uno de 9, 15 con una probabilidad de 1/12. Si prefiere obtener cada uno de los valores 9, 10, 11, 12, 13, 14, 15 con la misma probabilidad, puede usar randB
en su lugar, que presentaremos ahora.
Segunda interpretación de la pregunta (randB
)
randB
es una variante con semántica diferente. randBx
calcula el mismo intervalo de coma flotante [(3/4)*x, (5/4)*x), but its result (after full expansion) is a uniformly-chosen random integer between the ceil()
of the interval’s lower bound and the floor()
of its upper bound. This implies that randB12
can expand to each of the integers 9, 10, 11, 12, 13, 14, 15 with the same probability, namely 1/7. This will be shown in the benchmark below.
The code
documentclassarticle
usepackagexparse
ExplSyntaxOn
NewExpandableDocumentCommand randA m
fp_eval:n round( 0.5*(#1)*(rand() + 1.5) )
NewExpandableDocumentCommand randB m
fp_eval:n randint( ceil(0.75*(#1)), floor(1.25*(#1)) )
ExplSyntaxOff
begindocument
randA10
randB10
enddocument
Due to the randomness, the output will vary when you recompile this document.
A benchmark comparing both functions
documentclassarticle
usepackagexparse
usepackagexfp
usepackagebooktabs
usepackagefloatrow
usepackagesiunitx
sisetupround-mode = places, round-precision=4
ExplSyntaxOn
NewExpandableDocumentCommand randA m
fp_eval:n round( 0.5*(#1)*(rand() + 1.5) )
NewExpandableDocumentCommand randB m
fp_eval:n randint( ceil(0.75*(#1)), floor(1.25*(#1)) )
% Code for the benchmark
prop_new:N l_my_prop % nb of occurrences for each obtained result
int_new:N l_my_value_int
int_new:N l_my_count_int
seq_new:N l_my_values_seq
tl_new:N l_my_tabular_data_tl
cs_generate_variant:Nn prop_put:Nnn NVx
cs_new_protected:Npn my_benchmark:nn #1#2
prop_clear:N l_my_prop
int_step_inline:nn #1
int_set:Nn l_my_value_int #2
prop_if_in:NVTF l_my_prop l_my_value_int
prop_get:NVN l_my_prop l_my_value_int l_tmpa_tl
int_set:Nn l_my_count_int 1 + l_tmpa_tl
prop_put:NVx l_my_prop l_my_value_int
int_use:N l_my_count_int
prop_put:NVn l_my_prop l_my_value_int 1
NewDocumentCommand runAndDisplayBenchmark m m
my_benchmark:nn #1 #2
seq_clear:N l_my_values_seq
prop_map_inline:Nn l_my_prop
seq_put_right:Nn l_my_values_seq ##1 ##2
seq_sort:Nn l_my_values_seq
int_compare:nNnTF use_i:nn ##1 > use_i:nn ##2
sort_return_swapped:
sort_return_same:
tl_clear:N l_my_tabular_tl
seq_map_inline:Nn l_my_values_seq
tl_put_right:Nn l_my_tabular_data_tl
use_i:nn ##1 & fp_eval:n use_ii:nn ##1 / (#1) \
begintabularrS
toprule
Value & Frequency \ midrule
tl_use:N l_my_tabular_data_tl
bottomrule
endtabular
ExplSyntaxOff
newcommandnumberOfTests10000
begindocument
begintable
floatsetuprowfill=yes, captionskip=8pt
beginfloatrow[2]
hfil ttabbox runAndDisplayBenchmark numberOfTests randA 12 caption texttt string randA% hfil ttabbox runAndDisplayBenchmark numberOfTests randB 12 caption texttt string randB% hfil end floatrow end tabla sección * texttt string randA Como se explicó anteriormente en la respuesta, las probabilidades con verb | randA 12 | son: begin itemize item $ 1/6 approx num fpeval 1/6 $ para los valores 10, 11, 12, 13 y 14; item $ 1/12 approx num fpeval 1/12 $ para los valores 9 y 15. end itemize section * texttt string randB Si todos los valores posibles se eligen con la misma probabilidad, que debería ser el caso de verb | randB |, entonces la probabilidad de cada valor posible obtenido con verb | randB 12 | es $ 1/7 approx num fpeval 1/7 $. end documento
Aquí hay un resultado que obtuve. Debido a la aleatoriedad, por supuesto, es probable que obtenga resultados ligeramente diferentes si ejecuta este punto de referencia usted mismo.
Nota
- Los paréntesis denotan los extremos abiertos de un intervalo. Por ejemplo, [1,2] contiene todos los números de coma flotante x con 1 ≤ x ≤ 2, mientras que [1,2) is the same set with number 2 removed, i.e.: all floating point numbers x with 1 ≤ x < 2.
My comment turned into an answer. Note that there was a typo in the name, it should have been int_rand:nn
. It will evaluate the expressions as pure integer expressions (so no floats allowed as input):
documentclass[]artículo usepackage xparse ExplSyntaxOn NewExpandableDocumentCommand randomint mm int_rand: nn # 1 # 2 ExplSyntaxOff begin document randomint 8-8 / 4 8+ 8/4 end document
Entonces, usando solo un argumento (aún con expresión entera, ya que los flotantes ya están cubiertos por @frougon), podría usar:
documentclass[]article
usepackagexparse
ExplSyntaxOn
NewExpandableDocumentCommand randomint m
int_rand:nn #1 - #1/4 #1 + #1/4
ExplSyntaxOff
begindocument
randomint8
enddocument
Se podría hacer con pgf/tikz
paquete
documentclassarticle
usepackagepgf
pgfmathsetseednumberpdfrandomseed % to ensure that it is randomized
% use randomseed for xelatex
newcommandthecmd[1]%
pgfmathsetmacroaint(#1-#1/4)%
pgfmathsetmacrobint(#1+#1/4)%
pgfmathsetmacrothenumint(random(a,b))%
thenum%
%
begindocument
thecmd10
enddocument
EDITAR A pesar de que fue aceptado, lo mejoraré con la ayuda de los comentarios de @ Schrödinger’scat
int()
truncar el número. Esto conduce a un error. Con el código anterior, obtendré un número entre $textint(10-frac104)=textint(7.5)=7$
y $textint(10+frac104)=textint(12.5)=12$
. Entonces, un número entre $7$
y $12$
, pero $7$
no esta entre $7.5$
y $12.5$
, por lo que no debería ser una posibilidad. Una mejora del código podría ser:
documentclassarticle
usepackagepgf
pgfmathsetseednumberpdfrandomseed % to ensure that it is randomized
% use randomseed for xelatex
newcommandthecmd[1]%
pgfmathsetmacrothenumint(random(ceil(#1-#1/4),floor(#1+#1/4)))%
thenum%
%
begindocument
thecmd10
enddocument
Ya que ceil()
redondear el número y floor()
redondear el número hacia abajo, el código anterior produce un número entre $textceil(7.5)=8$
y $textfloor(12.5)=12$
Reseñas y puntuaciones de la guía
Puedes añadir valor a nuestra información colaborando tu veteranía en las interpretaciones.