mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
random.c
00001 /* 00002 ** random.c - Random module 00003 ** 00004 ** See Copyright Notice in mruby.h 00005 */ 00006 00007 #include "mruby.h" 00008 #include "mruby/variable.h" 00009 #include "mruby/class.h" 00010 #include "mruby/data.h" 00011 #include "mruby/array.h" 00012 #include "mt19937ar.h" 00013 00014 #include <time.h> 00015 00016 static char const MT_STATE_KEY[] = "$mrb_i_mt_state"; 00017 00018 static const struct mrb_data_type mt_state_type = { 00019 MT_STATE_KEY, mrb_free, 00020 }; 00021 00022 static mrb_value mrb_random_rand(mrb_state *mrb, mrb_value self); 00023 static mrb_value mrb_random_srand(mrb_state *mrb, mrb_value self); 00024 00025 static void 00026 mt_srand(mt_state *t, unsigned long seed) 00027 { 00028 mrb_random_init_genrand(t, seed); 00029 } 00030 00031 static unsigned long 00032 mt_rand(mt_state *t) 00033 { 00034 return mrb_random_genrand_int32(t); 00035 } 00036 00037 static double 00038 mt_rand_real(mt_state *t) 00039 { 00040 return mrb_random_genrand_real1(t); 00041 } 00042 00043 static mrb_value 00044 mrb_random_mt_srand(mrb_state *mrb, mt_state *t, mrb_value seed) 00045 { 00046 if (mrb_nil_p(seed)) { 00047 seed = mrb_fixnum_value((mrb_int)(time(NULL) + mt_rand(t))); 00048 if (mrb_fixnum(seed) < 0) { 00049 seed = mrb_fixnum_value(0 - mrb_fixnum(seed)); 00050 } 00051 } 00052 00053 mt_srand(t, (unsigned) mrb_fixnum(seed)); 00054 00055 return seed; 00056 } 00057 00058 static mrb_value 00059 mrb_random_mt_rand(mrb_state *mrb, mt_state *t, mrb_value max) 00060 { 00061 mrb_value value; 00062 00063 if (mrb_fixnum(max) == 0) { 00064 value = mrb_float_value(mrb, mt_rand_real(t)); 00065 } 00066 else { 00067 value = mrb_fixnum_value(mt_rand(t) % mrb_fixnum(max)); 00068 } 00069 00070 return value; 00071 } 00072 00073 static mrb_value 00074 get_opt(mrb_state* mrb) 00075 { 00076 mrb_value arg; 00077 00078 arg = mrb_nil_value(); 00079 mrb_get_args(mrb, "|o", &arg); 00080 00081 if (!mrb_nil_p(arg)) { 00082 if (!mrb_fixnum_p(arg)) { 00083 mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); 00084 } 00085 arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int"); 00086 if (mrb_fixnum(arg) < 0) { 00087 arg = mrb_fixnum_value(0 - mrb_fixnum(arg)); 00088 } 00089 } 00090 return arg; 00091 } 00092 00093 static mrb_value 00094 get_random(mrb_state *mrb) { 00095 return mrb_const_get(mrb, 00096 mrb_obj_value(mrb_class_get(mrb, "Random")), 00097 mrb_intern_lit(mrb, "DEFAULT")); 00098 } 00099 00100 static mt_state * 00101 get_random_state(mrb_state *mrb) 00102 { 00103 mrb_value random_val = get_random(mrb); 00104 return DATA_GET_PTR(mrb, random_val, &mt_state_type, mt_state); 00105 } 00106 00107 static mrb_value 00108 mrb_random_g_rand(mrb_state *mrb, mrb_value self) 00109 { 00110 mrb_value random = get_random(mrb); 00111 return mrb_random_rand(mrb, random); 00112 } 00113 00114 static mrb_value 00115 mrb_random_g_srand(mrb_state *mrb, mrb_value self) 00116 { 00117 mrb_value random = get_random(mrb); 00118 return mrb_random_srand(mrb, random); 00119 } 00120 00121 static mrb_value 00122 mrb_random_init(mrb_state *mrb, mrb_value self) 00123 { 00124 mrb_value seed; 00125 mt_state *t; 00126 00127 /* avoid memory leaks */ 00128 t = (mt_state*)DATA_PTR(self); 00129 if (t) { 00130 mrb_free(mrb, t); 00131 } 00132 mrb_data_init(self, NULL, &mt_state_type); 00133 00134 t = (mt_state *)mrb_malloc(mrb, sizeof(mt_state)); 00135 t->mti = N + 1; 00136 00137 seed = get_opt(mrb); 00138 seed = mrb_random_mt_srand(mrb, t, seed); 00139 if (mrb_nil_p(seed)) { 00140 t->has_seed = FALSE; 00141 } 00142 else { 00143 mrb_assert(mrb_fixnum_p(seed)); 00144 t->has_seed = TRUE; 00145 t->seed = mrb_fixnum(seed); 00146 } 00147 00148 mrb_data_init(self, t, &mt_state_type); 00149 00150 return self; 00151 } 00152 00153 static void 00154 mrb_random_rand_seed(mrb_state *mrb, mt_state *t) 00155 { 00156 if (!t->has_seed) { 00157 mrb_random_mt_srand(mrb, t, mrb_nil_value()); 00158 } 00159 } 00160 00161 static mrb_value 00162 mrb_random_rand(mrb_state *mrb, mrb_value self) 00163 { 00164 mrb_value max; 00165 mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state); 00166 00167 max = get_opt(mrb); 00168 mrb_random_rand_seed(mrb, t); 00169 return mrb_random_mt_rand(mrb, t, max); 00170 } 00171 00172 static mrb_value 00173 mrb_random_srand(mrb_state *mrb, mrb_value self) 00174 { 00175 mrb_value seed; 00176 mrb_value old_seed; 00177 mt_state *t = DATA_GET_PTR(mrb, self, &mt_state_type, mt_state); 00178 00179 seed = get_opt(mrb); 00180 seed = mrb_random_mt_srand(mrb, t, seed); 00181 old_seed = t->has_seed? mrb_fixnum_value(t->seed) : mrb_nil_value(); 00182 if (mrb_nil_p(seed)) { 00183 t->has_seed = FALSE; 00184 } 00185 else { 00186 mrb_assert(mrb_fixnum_p(seed)); 00187 t->has_seed = TRUE; 00188 t->seed = mrb_fixnum(seed); 00189 } 00190 00191 return old_seed; 00192 } 00193 00194 /* 00195 * call-seq: 00196 * ary.shuffle! -> ary 00197 * 00198 * Shuffles elements in self in place. 00199 */ 00200 00201 static mrb_value 00202 mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) 00203 { 00204 mrb_int i; 00205 mt_state *random = NULL; 00206 00207 if (RARRAY_LEN(ary) > 1) { 00208 mrb_get_args(mrb, "|d", &random, &mt_state_type); 00209 00210 if (random == NULL) { 00211 random = get_random_state(mrb); 00212 } 00213 mrb_random_rand_seed(mrb, random); 00214 00215 mrb_ary_modify(mrb, mrb_ary_ptr(ary)); 00216 00217 for (i = RARRAY_LEN(ary) - 1; i > 0; i--) { 00218 mrb_int j; 00219 mrb_value tmp; 00220 00221 j = mrb_fixnum(mrb_random_mt_rand(mrb, random, mrb_fixnum_value(RARRAY_LEN(ary)))); 00222 00223 tmp = RARRAY_PTR(ary)[i]; 00224 mrb_ary_ptr(ary)->ptr[i] = RARRAY_PTR(ary)[j]; 00225 mrb_ary_ptr(ary)->ptr[j] = tmp; 00226 } 00227 } 00228 00229 return ary; 00230 } 00231 00232 /* 00233 * call-seq: 00234 * ary.shuffle -> new_ary 00235 * 00236 * Returns a new array with elements of self shuffled. 00237 */ 00238 00239 static mrb_value 00240 mrb_ary_shuffle(mrb_state *mrb, mrb_value ary) 00241 { 00242 mrb_value new_ary = mrb_ary_new_from_values(mrb, RARRAY_LEN(ary), RARRAY_PTR(ary)); 00243 mrb_ary_shuffle_bang(mrb, new_ary); 00244 00245 return new_ary; 00246 } 00247 00248 /* 00249 * call-seq: 00250 * ary.sample -> obj 00251 * ary.sample(n) -> new_ary 00252 * 00253 * Choose a random element or +n+ random elements from the array. 00254 * 00255 * The elements are chosen by using random and unique indices into the array 00256 * in order to ensure that an element doesn't repeat itself unless the array 00257 * already contained duplicate elements. 00258 * 00259 * If the array is empty the first form returns +nil+ and the second form 00260 * returns an empty array. 00261 */ 00262 00263 static mrb_value 00264 mrb_ary_sample(mrb_state *mrb, mrb_value ary) 00265 { 00266 mrb_int n = 0; 00267 mrb_bool given; 00268 mt_state *random = NULL; 00269 mrb_int len = RARRAY_LEN(ary); 00270 00271 mrb_get_args(mrb, "|i?d", &n, &given, &random, &mt_state_type); 00272 if (random == NULL) { 00273 random = get_random_state(mrb); 00274 } 00275 mrb_random_rand_seed(mrb, random); 00276 mt_rand(random); 00277 if (!given) { /* pick one element */ 00278 switch (len) { 00279 case 0: 00280 return mrb_nil_value(); 00281 case 1: 00282 return RARRAY_PTR(ary)[0]; 00283 default: 00284 return RARRAY_PTR(ary)[mt_rand(random) % len]; 00285 } 00286 } 00287 else { 00288 mrb_value result; 00289 mrb_int i, j; 00290 00291 if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number"); 00292 if (n > len) n = len; 00293 result = mrb_ary_new_capa(mrb, n); 00294 for (i=0; i<n; i++) { 00295 mrb_int r; 00296 00297 for (;;) { 00298 retry: 00299 r = mt_rand(random) % len; 00300 00301 for (j=0; j<i; j++) { 00302 if (mrb_fixnum(RARRAY_PTR(result)[j]) == r) { 00303 goto retry; /* retry if duplicate */ 00304 } 00305 } 00306 break; 00307 } 00308 mrb_ary_push(mrb, result, mrb_fixnum_value(r)); 00309 } 00310 for (i=0; i<n; i++) { 00311 mrb_ary_set(mrb, result, i, RARRAY_PTR(ary)[mrb_fixnum(RARRAY_PTR(result)[i])]); 00312 } 00313 return result; 00314 } 00315 } 00316 00317 00318 void mrb_mruby_random_gem_init(mrb_state *mrb) 00319 { 00320 struct RClass *random; 00321 struct RClass *array = mrb->array_class; 00322 00323 mrb_define_method(mrb, mrb->kernel_module, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); 00324 mrb_define_method(mrb, mrb->kernel_module, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); 00325 00326 random = mrb_define_class(mrb, "Random", mrb->object_class); 00327 MRB_SET_INSTANCE_TT(random, MRB_TT_DATA); 00328 mrb_define_class_method(mrb, random, "rand", mrb_random_g_rand, MRB_ARGS_OPT(1)); 00329 mrb_define_class_method(mrb, random, "srand", mrb_random_g_srand, MRB_ARGS_OPT(1)); 00330 00331 mrb_define_method(mrb, random, "initialize", mrb_random_init, MRB_ARGS_OPT(1)); 00332 mrb_define_method(mrb, random, "rand", mrb_random_rand, MRB_ARGS_OPT(1)); 00333 mrb_define_method(mrb, random, "srand", mrb_random_srand, MRB_ARGS_OPT(1)); 00334 00335 mrb_define_method(mrb, array, "shuffle", mrb_ary_shuffle, MRB_ARGS_OPT(1)); 00336 mrb_define_method(mrb, array, "shuffle!", mrb_ary_shuffle_bang, MRB_ARGS_OPT(1)); 00337 mrb_define_method(mrb, array, "sample", mrb_ary_sample, MRB_ARGS_OPT(2)); 00338 00339 mrb_const_set(mrb, mrb_obj_value(random), mrb_intern_lit(mrb, "DEFAULT"), 00340 mrb_obj_new(mrb, random, 0, NULL)); 00341 } 00342 00343 void mrb_mruby_random_gem_final(mrb_state *mrb) 00344 { 00345 } 00346
Generated on Tue Jul 12 2022 18:00:35 by 1.7.2