Saltar al contenido

¿Cómo obtener un número aleatorio dentro de un rango?

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.

Resultados comparativos


Nota

  1. 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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *