Numworks Epsilon  1.4.1
Graphing Calculator Operating System
modurandom.c
Go to the documentation of this file.
1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * The MIT License (MIT)
5  *
6  * Copyright (c) 2016 Paul Sokolovsky
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  */
26 
27 #include <assert.h>
28 #include <string.h>
29 
30 #include "py/runtime.h"
31 
32 #if MICROPY_PY_URANDOM
33 
34 // Yasmarang random number generator
35 // by Ilya Levin
36 // http://www.literatecode.com/yasmarang
37 // Public Domain
38 
39 STATIC uint32_t yasmarang_pad = 0xeda4baba, yasmarang_n = 69, yasmarang_d = 233;
40 STATIC uint8_t yasmarang_dat = 0;
41 
42 STATIC uint32_t yasmarang(void)
43 {
44  yasmarang_pad += yasmarang_dat + yasmarang_d * yasmarang_n;
45  yasmarang_pad = (yasmarang_pad<<3) + (yasmarang_pad>>29);
46  yasmarang_n = yasmarang_pad | 2;
47  yasmarang_d ^= (yasmarang_pad<<31) + (yasmarang_pad>>1);
48  yasmarang_dat ^= (char) yasmarang_pad ^ (yasmarang_d>>8) ^ 1;
49 
50  return (yasmarang_pad^(yasmarang_d<<5)^(yasmarang_pad>>18)^(yasmarang_dat<<1));
51 } /* yasmarang */
52 
53 // End of Yasmarang
54 
55 #if MICROPY_PY_URANDOM_EXTRA_FUNCS
56 
57 // returns an unsigned integer below the given argument
58 // n must not be zero
59 STATIC uint32_t yasmarang_randbelow(uint32_t n) {
60  uint32_t mask = 1;
61  while ((n & mask) < n) {
62  mask = (mask << 1) | 1;
63  }
64  uint32_t r;
65  do {
66  r = yasmarang() & mask;
67  } while (r >= n);
68  return r;
69 }
70 
71 #endif
72 
73 STATIC mp_obj_t mod_urandom_getrandbits(mp_obj_t num_in) {
74  int n = mp_obj_get_int(num_in);
75  if (n > 32 || n == 0) {
77  }
78  uint32_t mask = ~0;
79  // Beware of C undefined behavior when shifting by >= than bit size
80  mask >>= (32 - n);
81  return mp_obj_new_int_from_uint(yasmarang() & mask);
82 }
83 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_getrandbits_obj, mod_urandom_getrandbits);
84 
85 STATIC mp_obj_t mod_urandom_seed(mp_obj_t seed_in) {
86  mp_uint_t seed = mp_obj_get_int_truncated(seed_in);
87  yasmarang_pad = seed;
88  yasmarang_n = 69;
89  yasmarang_d = 233;
90  yasmarang_dat = 0;
91  return mp_const_none;
92 }
93 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_seed_obj, mod_urandom_seed);
94 
95 #if MICROPY_PY_URANDOM_EXTRA_FUNCS
96 
97 STATIC mp_obj_t mod_urandom_randrange(size_t n_args, const mp_obj_t *args) {
99  if (n_args == 1) {
100  // range(stop)
101  if (start > 0) {
102  return mp_obj_new_int(yasmarang_randbelow(start));
103  } else {
104  goto error;
105  }
106  } else {
107  mp_int_t stop = mp_obj_get_int(args[1]);
108  if (n_args == 2) {
109  // range(start, stop)
110  if (start < stop) {
111  return mp_obj_new_int(start + yasmarang_randbelow(stop - start));
112  } else {
113  goto error;
114  }
115  } else {
116  // range(start, stop, step)
117  mp_int_t step = mp_obj_get_int(args[2]);
118  mp_int_t n;
119  if (step > 0) {
120  n = (stop - start + step - 1) / step;
121  } else if (step < 0) {
122  n = (stop - start + step + 1) / step;
123  } else {
124  goto error;
125  }
126  if (n > 0) {
127  return mp_obj_new_int(start + step * yasmarang_randbelow(n));
128  } else {
129  goto error;
130  }
131  }
132  }
133 
134 error:
136 }
137 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_urandom_randrange_obj, 1, 3, mod_urandom_randrange);
138 
139 STATIC mp_obj_t mod_urandom_randint(mp_obj_t a_in, mp_obj_t b_in) {
140  mp_int_t a = mp_obj_get_int(a_in);
141  mp_int_t b = mp_obj_get_int(b_in);
142  if (a <= b) {
143  return mp_obj_new_int(a + yasmarang_randbelow(b - a + 1));
144  } else {
146  }
147 }
148 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_randint_obj, mod_urandom_randint);
149 
150 STATIC mp_obj_t mod_urandom_choice(mp_obj_t seq) {
151  mp_int_t len = mp_obj_get_int(mp_obj_len(seq));
152  if (len > 0) {
153  return mp_obj_subscr(seq, mp_obj_new_int(yasmarang_randbelow(len)), MP_OBJ_SENTINEL);
154  } else {
156  }
157 }
158 STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_urandom_choice_obj, mod_urandom_choice);
159 
160 #if MICROPY_PY_BUILTINS_FLOAT
161 
162 // returns a number in the range [0..1) using Yasmarang to fill in the fraction bits
163 STATIC mp_float_t yasmarang_float(void) {
164  #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
165  typedef uint64_t mp_float_int_t;
166  #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
167  typedef uint32_t mp_float_int_t;
168  #endif
169  union {
170  mp_float_t f;
171  #if MP_ENDIANNESS_LITTLE
172  struct { mp_float_int_t frc:MP_FLOAT_FRAC_BITS, exp:MP_FLOAT_EXP_BITS, sgn:1; } p;
173  #else
174  struct { mp_float_int_t sgn:1, exp:MP_FLOAT_EXP_BITS, frc:MP_FLOAT_FRAC_BITS; } p;
175  #endif
176  } u;
177  u.p.sgn = 0;
178  u.p.exp = (1 << (MP_FLOAT_EXP_BITS - 1)) - 1;
179  if (MP_FLOAT_FRAC_BITS <= 32) {
180  u.p.frc = yasmarang();
181  } else {
182  u.p.frc = ((uint64_t)yasmarang() << 32) | (uint64_t)yasmarang();
183  }
184  return u.f - 1;
185 }
186 
187 STATIC mp_obj_t mod_urandom_random(void) {
188  return mp_obj_new_float(yasmarang_float());
189 }
190 STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_urandom_random_obj, mod_urandom_random);
191 
192 STATIC mp_obj_t mod_urandom_uniform(mp_obj_t a_in, mp_obj_t b_in) {
193  mp_float_t a = mp_obj_get_float(a_in);
194  mp_float_t b = mp_obj_get_float(b_in);
195  return mp_obj_new_float(a + (b - a) * yasmarang_float());
196 }
197 STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_urandom_uniform_obj, mod_urandom_uniform);
198 
199 #endif
200 
201 #endif // MICROPY_PY_URANDOM_EXTRA_FUNCS
202 
203 STATIC const mp_rom_map_elem_t mp_module_urandom_globals_table[] = {
204  { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_urandom) },
205  { MP_ROM_QSTR(MP_QSTR_getrandbits), MP_ROM_PTR(&mod_urandom_getrandbits_obj) },
206  { MP_ROM_QSTR(MP_QSTR_seed), MP_ROM_PTR(&mod_urandom_seed_obj) },
207  #if MICROPY_PY_URANDOM_EXTRA_FUNCS
208  { MP_ROM_QSTR(MP_QSTR_randrange), MP_ROM_PTR(&mod_urandom_randrange_obj) },
209  { MP_ROM_QSTR(MP_QSTR_randint), MP_ROM_PTR(&mod_urandom_randint_obj) },
210  { MP_ROM_QSTR(MP_QSTR_choice), MP_ROM_PTR(&mod_urandom_choice_obj) },
211  #if MICROPY_PY_BUILTINS_FLOAT
212  { MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&mod_urandom_random_obj) },
213  { MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&mod_urandom_uniform_obj) },
214  #endif
215  #endif
216 };
217 
218 STATIC MP_DEFINE_CONST_DICT(mp_module_urandom_globals, mp_module_urandom_globals_table);
219 
221  .base = { &mp_type_module },
222  .globals = (mp_obj_dict_t*)&mp_module_urandom_globals,
223 };
224 
225 #endif //MICROPY_PY_URANDOM
#define exp(x)
Definition: math.h:176
intptr_t mp_int_t
Definition: mpconfigport.h:73
uintptr_t mp_uint_t
Definition: mpconfigport.h:74
#define mp_const_none
Definition: obj.h:614
#define MP_DEFINE_CONST_DICT(dict_name, table_name)
Definition: obj.h:317
mp_obj_t mp_obj_new_exception(const mp_obj_type_t *exc_type)
Definition: objexcept.c:329
#define MP_OBJ_SENTINEL
Definition: obj.h:75
#define MP_ROM_QSTR(q)
Definition: obj.h:241
#define MP_ROM_PTR(p)
Definition: obj.h:242
mp_obj_base_t base
Definition: obj.h:814
unsigned char uint8_t
Definition: stdint.h:4
mp_int_t mp_obj_get_int(mp_const_obj_t arg)
Definition: obj.c:225
#define STATIC
Definition: mpconfig.h:1178
#define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name)
Definition: obj.h:285
const mp_obj_module_t mp_module_urandom
unsigned int uint32_t
Definition: stdint.h:6
#define NULL
Definition: stddef.h:4
unsigned long long uint64_t
Definition: stdint.h:7
mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value)
Definition: objint.c:343
args
Definition: i18n.py:175
mp_obj_t mp_obj_new_int(mp_int_t value)
Definition: objint.c:353
#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name)
Definition: obj.h:297
void start()
Definition: rt0.cpp:31
#define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name)
Definition: obj.h:282
const mp_obj_type_t mp_type_IndexError
#define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name)
Definition: obj.h:288
NORETURN void mp_raise_ValueError(const char *msg)
Definition: runtime.c:1456
const mp_obj_type_t mp_type_module
Definition: objmodule.c:94
#define nlr_raise(val)
Definition: nlr.h:89
uint64_t mp_obj_t
Definition: obj.h:39
mp_obj_t mp_obj_len(mp_obj_t o_in)
Definition: obj.c:433
mp_obj_t mp_obj_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value)
Definition: obj.c:467
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg)
Definition: obj.c:247