@@ -201,6 +201,8 @@ static inline uint32 randomMT(void)
201
201
#define PHP_RAND_MAX RAND_MAX
202
202
#endif
203
203
204
+ /* {{{ proto void srand(int seed)
205
+ Seeds random number generator */
204
206
PHP_FUNCTION (srand )
205
207
{
206
208
pval * arg ;
@@ -219,7 +221,10 @@ PHP_FUNCTION(srand)
219
221
#endif
220
222
#endif
221
223
}
224
+ /* }}} */
222
225
226
+ /* {{{ proto void mt_srand(int seed)
227
+ Seeds Mersenne Twister random number generator */
223
228
PHP_FUNCTION (mt_srand )
224
229
{
225
230
pval * arg ;
@@ -229,7 +234,10 @@ PHP_FUNCTION(mt_srand)
229
234
convert_to_long (arg );
230
235
seedMT (arg -> value .lval );
231
236
}
237
+ /* }}} */
232
238
239
+ /* {{{ proto int rand([int min, int max])
240
+ Returns a random number */
233
241
PHP_FUNCTION (rand )
234
242
{
235
243
pval * p_min = NULL , * p_max = NULL ;
@@ -262,13 +270,40 @@ PHP_FUNCTION(rand)
262
270
return_value -> value .lval = rand ();
263
271
#endif
264
272
#endif
265
-
273
+ /*
274
+ * A bit of tricky math here. We want to avoid using a modulus because
275
+ * that simply tosses the high-order bits and might skew the distribution
276
+ * of random values over the range. Instead we map the range directly.
277
+ *
278
+ * We need to map the range from 0...M evenly to the range a...b
279
+ * Let n = the random number and n' = the mapped random number
280
+ *
281
+ * Then we have: n' = a + n(b-a)/M
282
+ *
283
+ * We have a problem here in that only n==M will get mapped to b which
284
+ # means the chances of getting b is much much less than getting any of
285
+ # the other values in the range. We can fix this by increasing our range
286
+ # artifically and using:
287
+ #
288
+ # n' = a + n(b-a+1)/M
289
+ *
290
+ # Now we only have a problem if n==M which would cause us to produce a
291
+ # number of b+1 which would be bad. So we bump M up by one to make sure
292
+ # this will never happen, and the final algorithm looks like this:
293
+ #
294
+ # n' = a + n(b-a+1)/(M+1)
295
+ *
296
+ * -RL
297
+ */
266
298
if (p_min && p_max ) { /* implement range */
267
299
return_value -> value .lval = p_min -> value .lval +
268
- (int )((double )p_max -> value .lval * return_value -> value .lval /( PHP_RAND_MAX + ( double ) p_min -> value .lval ));
300
+ (int )((double )( p_max -> value .lval - p_min -> value .lval + 1 ) * return_value -> value .lval /( PHP_RAND_MAX + 1.0 ));
269
301
}
270
302
}
303
+ /* }}} */
271
304
305
+ /* {{{ proto int mt_rand([int min, int max])
306
+ Returns a random number from Mersenne Twister */
272
307
PHP_FUNCTION (mt_rand )
273
308
{
274
309
pval * p_min = NULL , * p_max = NULL ;
@@ -304,16 +339,23 @@ PHP_FUNCTION(mt_rand)
304
339
305
340
if (p_min && p_max ) { /* implement range */
306
341
return_value -> value .lval = p_min -> value .lval +
307
- (int )((double )p_max -> value .lval * return_value -> value .lval /( PHP_RAND_MAX + ( double ) p_min -> value .lval ));
342
+ (int )((double )( p_max -> value .lval - p_min -> value .lval + 1 ) * return_value -> value .lval /( PHP_RAND_MAX + 1.0 ));
308
343
}
309
344
}
345
+ /* }}} */
310
346
347
+ /* {{{ proto int getrandmax(void)
348
+ Returns the maximum value a random number can have */
311
349
PHP_FUNCTION (getrandmax )
312
350
{
313
351
return_value -> type = IS_LONG ;
314
352
return_value -> value .lval = PHP_RAND_MAX ;
315
353
}
354
+ /* }}} */
355
+
316
356
357
+ /* {{{ proto int mt_getrandmax(void)
358
+ Returns the maximum value a random number from Mersenne Twister can have */
317
359
PHP_FUNCTION (mt_getrandmax )
318
360
{
319
361
return_value -> type = IS_LONG ;
@@ -323,7 +365,7 @@ PHP_FUNCTION(mt_getrandmax)
323
365
*/
324
366
return_value -> value .lval = 2147483647 ; /* 2^^31 */
325
367
}
326
-
368
+ /* }}} */
327
369
/*
328
370
* Local variables:
329
371
* tab-width: 4
0 commit comments