Skip to content

Commit 8de0737

Browse files
committed
Bring rand.c up to date
1 parent cd8d7c7 commit 8de0737

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

ext/standard/rand.c

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,8 @@ static inline uint32 randomMT(void)
201201
#define PHP_RAND_MAX RAND_MAX
202202
#endif
203203

204+
/* {{{ proto void srand(int seed)
205+
Seeds random number generator */
204206
PHP_FUNCTION(srand)
205207
{
206208
pval *arg;
@@ -219,7 +221,10 @@ PHP_FUNCTION(srand)
219221
#endif
220222
#endif
221223
}
224+
/* }}} */
222225

226+
/* {{{ proto void mt_srand(int seed)
227+
Seeds Mersenne Twister random number generator */
223228
PHP_FUNCTION(mt_srand)
224229
{
225230
pval *arg;
@@ -229,7 +234,10 @@ PHP_FUNCTION(mt_srand)
229234
convert_to_long(arg);
230235
seedMT(arg->value.lval);
231236
}
237+
/* }}} */
232238

239+
/* {{{ proto int rand([int min, int max])
240+
Returns a random number */
233241
PHP_FUNCTION(rand)
234242
{
235243
pval *p_min=NULL, *p_max=NULL;
@@ -262,13 +270,40 @@ PHP_FUNCTION(rand)
262270
return_value->value.lval = rand();
263271
#endif
264272
#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+
*/
266298
if (p_min && p_max) { /* implement range */
267299
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));
269301
}
270302
}
303+
/* }}} */
271304

305+
/* {{{ proto int mt_rand([int min, int max])
306+
Returns a random number from Mersenne Twister */
272307
PHP_FUNCTION(mt_rand)
273308
{
274309
pval *p_min=NULL, *p_max=NULL;
@@ -304,16 +339,23 @@ PHP_FUNCTION(mt_rand)
304339

305340
if (p_min && p_max) { /* implement range */
306341
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));
308343
}
309344
}
345+
/* }}} */
310346

347+
/* {{{ proto int getrandmax(void)
348+
Returns the maximum value a random number can have */
311349
PHP_FUNCTION(getrandmax)
312350
{
313351
return_value->type = IS_LONG;
314352
return_value->value.lval = PHP_RAND_MAX;
315353
}
354+
/* }}} */
355+
316356

357+
/* {{{ proto int mt_getrandmax(void)
358+
Returns the maximum value a random number from Mersenne Twister can have */
317359
PHP_FUNCTION(mt_getrandmax)
318360
{
319361
return_value->type = IS_LONG;
@@ -323,7 +365,7 @@ PHP_FUNCTION(mt_getrandmax)
323365
*/
324366
return_value->value.lval = 2147483647; /* 2^^31 */
325367
}
326-
368+
/* }}} */
327369
/*
328370
* Local variables:
329371
* tab-width: 4

0 commit comments

Comments
 (0)