Created
August 16, 2017 19:58
-
-
Save nikic/64e7ec58ebb6121d350fb80927a65082 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} | |
/* }}} */ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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