Skip to content

Instantly share code, notes, and snippets.

@nikic
Created August 16, 2017 19:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nikic/64e7ec58ebb6121d350fb80927a65082 to your computer and use it in GitHub Desktop.
Save nikic/64e7ec58ebb6121d350fb80927a65082 to your computer and use it in GitHub Desktop.
// Resulting code as the diff is hard to read
static uint32_t rand_range32(uint32_t umax) {
uint32_t result, limit;
result = php_mt_rand();
/* Special case where no modulus is required */
if (UNEXPECTED(umax == UINT32_MAX)) {
return result;
}
/* Increment the max so the range is inclusive of max */
umax++;
/* Powers of two are not biased */
if ((umax & (umax - 1)) == 0) {
return result & (umax - 1);
}
/* Ceiling under which UINT32_MAX % max == 0 */
limit = UINT32_MAX - (UINT32_MAX % umax) - 1;
/* Discard numbers over the limit to avoid modulo bias */
while (UNEXPECTED(result > limit)) {
result = php_mt_rand();
}
return result % umax;
}
#if ZEND_ULONG_MAX > UINT32_MAX
static uint64_t rand_range64(uint64_t umax) {
uint64_t result, limit;
result = php_mt_rand();
result = (result << 32) | php_mt_rand();
/* Special case where no modulus is required */
if (UNEXPECTED(umax == UINT64_MAX)) {
return result;
}
/* Increment the max so the range is inclusive of max */
umax++;
/* Powers of two are not biased */
if ((umax & (umax - 1)) == 0) {
return result & (umax - 1);
}
/* Ceiling under which UINT64_MAX % max == 0 */
limit = UINT64_MAX - (UINT64_MAX % umax) - 1;
/* Discard numbers over the limit to avoid modulo bias */
while (UNEXPECTED(result > limit)) {
result = php_mt_rand();
result = (result << 32) | php_mt_rand();
}
return result % umax;
}
#endif
/* {{{ php_mt_rand_range
*/
PHPAPI zend_long php_mt_rand_range(zend_long min, zend_long max)
{
zend_ulong umax = max - min;
#if ZEND_ULONG_MAX > UINT32_MAX
if (umax > UINT32_MAX) {
return (zend_long) (rand_range64(umax) + min);
}
#endif
return (zend_long) (rand_range32(umax) + min);
}
/* }}} */
diff --git a/ext/standard/mt_rand.c b/ext/standard/mt_rand.c
index 0e2fe51..3942ddc 100644
--- a/ext/standard/mt_rand.c
+++ b/ext/standard/mt_rand.c
@@ -209,50 +209,81 @@ PHP_FUNCTION(mt_srand)
}
/* }}} */
-/* {{{ php_mt_rand_range
- */
-PHPAPI zend_long php_mt_rand_range(zend_long min, zend_long max)
-{
- zend_ulong umax = max - min;
- zend_ulong limit;
- zend_ulong result;
+static uint32_t rand_range32(uint32_t umax) {
+ uint32_t result, limit;
result = php_mt_rand();
-#if ZEND_ULONG_MAX > UINT32_MAX
- if (umax > UINT32_MAX) {
- result = (result << 32) | php_mt_rand();
- }
-#endif
/* Special case where no modulus is required */
- if (UNEXPECTED(umax == ZEND_ULONG_MAX)) {
- return (zend_long)result;
+ if (UNEXPECTED(umax == UINT32_MAX)) {
+ return result;
}
/* Increment the max so the range is inclusive of max */
umax++;
/* Powers of two are not biased */
- if (EXPECTED((umax & (umax - 1)) != 0)) {
- /* Ceiling under which ZEND_LONG_MAX % max == 0 */
- limit = ZEND_ULONG_MAX - (ZEND_ULONG_MAX % umax) - 1;
+ if ((umax & (umax - 1)) == 0) {
+ return result & (umax - 1);
+ }
+
+ /* Ceiling under which UINT32_MAX % max == 0 */
+ limit = UINT32_MAX - (UINT32_MAX % umax) - 1;
+
+ /* Discard numbers over the limit to avoid modulo bias */
+ while (UNEXPECTED(result > limit)) {
+ result = php_mt_rand();
+ }
+
+ return result % umax;
+}
- /* Discard numbers over the limit to avoid modulo bias */
- while (UNEXPECTED(result > limit)) {
#if ZEND_ULONG_MAX > UINT32_MAX
- if (umax > UINT32_MAX) {
- result = (result << 32) | php_mt_rand();
- }
- else {
- result = php_mt_rand();
- }
-#else
- result = php_mt_rand();
+static uint64_t rand_range64(uint64_t umax) {
+ uint64_t result, limit;
+
+ result = php_mt_rand();
+ result = (result << 32) | php_mt_rand();
+
+ /* Special case where no modulus is required */
+ if (UNEXPECTED(umax == UINT64_MAX)) {
+ return result;
+ }
+
+ /* Increment the max so the range is inclusive of max */
+ umax++;
+
+ /* Powers of two are not biased */
+ if ((umax & (umax - 1)) == 0) {
+ return result & (umax - 1);
+ }
+
+ /* Ceiling under which UINT64_MAX % max == 0 */
+ limit = UINT64_MAX - (UINT64_MAX % umax) - 1;
+
+ /* Discard numbers over the limit to avoid modulo bias */
+ while (UNEXPECTED(result > limit)) {
+ result = php_mt_rand();
+ result = (result << 32) | php_mt_rand();
+ }
+
+ return result % umax;
+}
#endif
- }
+
+/* {{{ php_mt_rand_range
+ */
+PHPAPI zend_long php_mt_rand_range(zend_long min, zend_long max)
+{
+ zend_ulong umax = max - min;
+
+#if ZEND_ULONG_MAX > UINT32_MAX
+ if (umax > UINT32_MAX) {
+ return (zend_long) (rand_range64(umax) + min);
}
+#endif
- return (zend_long)((result % umax) + min);
+ return (zend_long) (rand_range32(umax) + min);
}
/* }}} */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment