@@ -53,6 +53,24 @@ STATIC uint32_t yasmarang(void)
5353
5454// End of Yasmarang
5555
56+ #if MICROPY_PY_URANDOM_EXTRA_FUNCS
57+
58+ // returns an unsigned integer below the given argument
59+ // n must not be zero
60+ STATIC uint32_t yasmarang_randbelow (uint32_t n ) {
61+ uint32_t mask = 1 ;
62+ while ((n & mask ) < n ) {
63+ mask = (mask << 1 ) | 1 ;
64+ }
65+ uint32_t r ;
66+ do {
67+ r = yasmarang () & mask ;
68+ } while (r >= n );
69+ return r ;
70+ }
71+
72+ #endif
73+
5674STATIC mp_obj_t mod_urandom_getrandbits (mp_obj_t num_in ) {
5775 int n = mp_obj_get_int (num_in );
5876 if (n > 32 || n == 0 ) {
@@ -75,10 +93,122 @@ STATIC mp_obj_t mod_urandom_seed(mp_obj_t seed_in) {
7593}
7694STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_urandom_seed_obj , mod_urandom_seed );
7795
96+ #if MICROPY_PY_URANDOM_EXTRA_FUNCS
97+
98+ STATIC mp_obj_t mod_urandom_randrange (size_t n_args , const mp_obj_t * args ) {
99+ mp_int_t start = mp_obj_get_int (args [0 ]);
100+ if (n_args == 1 ) {
101+ // range(stop)
102+ if (start > 0 ) {
103+ return mp_obj_new_int (yasmarang_randbelow (start ));
104+ } else {
105+ nlr_raise (mp_obj_new_exception (& mp_type_ValueError ));
106+ }
107+ } else {
108+ mp_int_t stop = mp_obj_get_int (args [1 ]);
109+ if (n_args == 2 ) {
110+ // range(start, stop)
111+ if (start < stop ) {
112+ return mp_obj_new_int (start + yasmarang_randbelow (stop - start ));
113+ } else {
114+ nlr_raise (mp_obj_new_exception (& mp_type_ValueError ));
115+ }
116+ } else {
117+ // range(start, stop, step)
118+ mp_int_t step = mp_obj_get_int (args [2 ]);
119+ mp_int_t n ;
120+ if (step > 0 ) {
121+ n = (stop - start + step - 1 ) / step ;
122+ } else if (step < 0 ) {
123+ n = (stop - start + step + 1 ) / step ;
124+ } else {
125+ nlr_raise (mp_obj_new_exception (& mp_type_ValueError ));
126+ }
127+ if (n > 0 ) {
128+ return mp_obj_new_int (start + step * yasmarang_randbelow (n ));
129+ } else {
130+ nlr_raise (mp_obj_new_exception (& mp_type_ValueError ));
131+ }
132+ }
133+ }
134+ }
135+ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN (mod_urandom_randrange_obj , 1 , 3 , mod_urandom_randrange );
136+
137+ STATIC mp_obj_t mod_urandom_randint (mp_obj_t a_in , mp_obj_t b_in ) {
138+ mp_int_t a = mp_obj_get_int (a_in );
139+ mp_int_t b = mp_obj_get_int (b_in );
140+ if (a <= b ) {
141+ return mp_obj_new_int (a + yasmarang_randbelow (b - a + 1 ));
142+ } else {
143+ nlr_raise (mp_obj_new_exception (& mp_type_ValueError ));
144+ }
145+ }
146+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (mod_urandom_randint_obj , mod_urandom_randint );
147+
148+ STATIC mp_obj_t mod_urandom_choice (mp_obj_t seq ) {
149+ mp_int_t len = mp_obj_get_int (mp_obj_len (seq ));
150+ if (len > 0 ) {
151+ return mp_obj_subscr (seq , mp_obj_new_int (yasmarang_randbelow (len )), MP_OBJ_SENTINEL );
152+ } else {
153+ nlr_raise (mp_obj_new_exception (& mp_type_IndexError ));
154+ }
155+ }
156+ STATIC MP_DEFINE_CONST_FUN_OBJ_1 (mod_urandom_choice_obj , mod_urandom_choice );
157+
158+ #if MICROPY_PY_BUILTINS_FLOAT
159+
160+ // returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
161+ STATIC mp_float_t yasmarang_float (void ) {
162+ #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
163+ typedef uint64_t mp_float_int_t ;
164+ #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
165+ typedef uint32_t mp_float_int_t ;
166+ #endif
167+ union {
168+ mp_float_t f ;
169+ #if MP_ENDIANNESS_LITTLE
170+ struct { mp_float_int_t frc :MP_FLOAT_FRAC_BITS , exp :MP_FLOAT_EXP_BITS , sgn :1 ; } p ;
171+ #else
172+ struct { mp_float_int_t sgn :1 , exp :MP_FLOAT_EXP_BITS , frc :MP_FLOAT_FRAC_BITS ; } p ;
173+ #endif
174+ } u ;
175+ u .p .sgn = 0 ;
176+ u .p .exp = (1 << (MP_FLOAT_EXP_BITS - 1 )) - 1 ;
177+ if (MP_FLOAT_FRAC_BITS <= 32 ) {
178+ u .p .frc = yasmarang ();
179+ } else {
180+ u .p .frc = ((uint64_t )yasmarang () << 32 ) | (uint64_t )yasmarang ();
181+ }
182+ return u .f - 1 ;
183+ }
184+
185+ STATIC mp_obj_t mod_urandom_random (void ) {
186+ return mp_obj_new_float (yasmarang_float ());
187+ }
188+ STATIC MP_DEFINE_CONST_FUN_OBJ_0 (mod_urandom_random_obj , mod_urandom_random );
189+
190+ STATIC mp_obj_t mod_urandom_uniform (mp_obj_t a_in , mp_obj_t b_in ) {
191+ mp_float_t a = mp_obj_get_float (a_in );
192+ mp_float_t b = mp_obj_get_float (b_in );
193+ return mp_obj_new_float (a + (b - a ) * yasmarang_float ());
194+ }
195+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (mod_urandom_uniform_obj , mod_urandom_uniform );
196+
197+ #endif
198+
199+ #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
200+
78201STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table [] = {
79202 { MP_ROM_QSTR (MP_QSTR___name__ ), MP_ROM_QSTR (MP_QSTR_urandom ) },
80203 { MP_ROM_QSTR (MP_QSTR_getrandbits ), MP_ROM_PTR (& mod_urandom_getrandbits_obj ) },
81204 { MP_ROM_QSTR (MP_QSTR_seed ), MP_ROM_PTR (& mod_urandom_seed_obj ) },
205+ #if MICROPY_PY_URANDOM_EXTRA_FUNCS
206+ { MP_ROM_QSTR (MP_QSTR_randrange ), MP_ROM_PTR (& mod_urandom_randrange_obj ) },
207+ { MP_ROM_QSTR (MP_QSTR_randint ), MP_ROM_PTR (& mod_urandom_randint_obj ) },
208+ { MP_ROM_QSTR (MP_QSTR_choice ), MP_ROM_PTR (& mod_urandom_choice_obj ) },
209+ { MP_ROM_QSTR (MP_QSTR_random ), MP_ROM_PTR (& mod_urandom_random_obj ) },
210+ { MP_ROM_QSTR (MP_QSTR_uniform ), MP_ROM_PTR (& mod_urandom_uniform_obj ) },
211+ #endif
82212};
83213
84214STATIC MP_DEFINE_CONST_DICT (mp_module_urandom_globals , mp_module_urandom_globals_table );
0 commit comments