Skip to content

Commit 8615e42

Browse files
committed
Merge branch 'pull-request/839' into PHP-5.6
* pull-request/839: Upated NEWS Address issues raised by @nikic Make sure min < max Mersenne Twister was added in GMP 4.2 Add test files Add gmp_random_bits(bits) and gmp_random_range(min, max) Change GMPs default PRNG to Mersenne Twister
2 parents 7acba33 + 106fab0 commit 8615e42

File tree

4 files changed

+241
-9
lines changed

4 files changed

+241
-9
lines changed

ext/gmp/gmp.c

Lines changed: 113 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
104104
ZEND_ARG_INFO(0, limiter)
105105
ZEND_END_ARG_INFO()
106106

107+
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_bits, 0, 0, 1)
108+
ZEND_ARG_INFO(0, bits)
109+
ZEND_END_ARG_INFO()
110+
111+
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_range, 0, 0, 2)
112+
ZEND_ARG_INFO(0, min)
113+
ZEND_ARG_INFO(0, max)
114+
ZEND_END_ARG_INFO()
115+
107116
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
108117
ZEND_ARG_INFO(0, a)
109118
ZEND_ARG_INFO(0, index)
@@ -161,6 +170,8 @@ const zend_function_entry gmp_functions[] = {
161170
ZEND_FE(gmp_cmp, arginfo_gmp_binary)
162171
ZEND_FE(gmp_sign, arginfo_gmp_unary)
163172
ZEND_FE(gmp_random, arginfo_gmp_random)
173+
ZEND_FE(gmp_random_bits, arginfo_gmp_random_bits)
174+
ZEND_FE(gmp_random_range, arginfo_gmp_random_range)
164175
ZEND_FE(gmp_and, arginfo_gmp_binary)
165176
ZEND_FE(gmp_or, arginfo_gmp_binary)
166177
ZEND_FE(gmp_com, arginfo_gmp_unary)
@@ -1784,6 +1795,22 @@ ZEND_FUNCTION(gmp_sign)
17841795
}
17851796
/* }}} */
17861797

1798+
static void gmp_init_random(TSRMLS_D)
1799+
{
1800+
if (!GMPG(rand_initialized)) {
1801+
/* Initialize */
1802+
#if GMP_42_OR_NEWER
1803+
gmp_randinit_mt(GMPG(rand_state));
1804+
#else
1805+
gmp_randinit_lc_2exp(GMPG(rand_state), 32L);
1806+
#endif
1807+
/* Seed */
1808+
gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
1809+
1810+
GMPG(rand_initialized) = 1;
1811+
}
1812+
}
1813+
17871814
/* {{{ proto GMP gmp_random([int limiter])
17881815
Gets random number */
17891816
ZEND_FUNCTION(gmp_random)
@@ -1796,16 +1823,8 @@ ZEND_FUNCTION(gmp_random)
17961823
}
17971824

17981825
INIT_GMP_RETVAL(gmpnum_result);
1826+
gmp_init_random(TSRMLS_C);
17991827

1800-
if (!GMPG(rand_initialized)) {
1801-
/* Initialize */
1802-
gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L);
1803-
1804-
/* Seed */
1805-
gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
1806-
1807-
GMPG(rand_initialized) = 1;
1808-
}
18091828
#ifdef GMP_LIMB_BITS
18101829
mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
18111830
#else
@@ -1814,6 +1833,91 @@ ZEND_FUNCTION(gmp_random)
18141833
}
18151834
/* }}} */
18161835

1836+
/* {{{ proto GMP gmp_random_bits(int bits)
1837+
Gets a random number in the range 0 to (2 ** n) - 1 */
1838+
ZEND_FUNCTION(gmp_random_bits)
1839+
{
1840+
long bits;
1841+
mpz_ptr gmpnum_result;
1842+
1843+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bits) == FAILURE) {
1844+
return;
1845+
}
1846+
1847+
if (bits <= 0) {
1848+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The number of bits must be positive");
1849+
RETURN_FALSE;
1850+
}
1851+
1852+
INIT_GMP_RETVAL(gmpnum_result);
1853+
gmp_init_random(TSRMLS_C);
1854+
1855+
mpz_urandomb(gmpnum_result, GMPG(rand_state), bits);
1856+
}
1857+
/* }}} */
1858+
1859+
/* {{{ proto GMP gmp_random_range(mixed min, mixed max)
1860+
Gets a random number in the range min to max */
1861+
ZEND_FUNCTION(gmp_random_range)
1862+
{
1863+
zval *min_arg, *max_arg;
1864+
mpz_ptr gmpnum_min, gmpnum_max, gmpnum_result;
1865+
gmp_temp_t temp_a, temp_b;
1866+
1867+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &min_arg, &max_arg) == FAILURE) {
1868+
return;
1869+
}
1870+
1871+
gmp_init_random(TSRMLS_C);
1872+
1873+
FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a);
1874+
1875+
if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
1876+
if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
1877+
FREE_GMP_TEMP(temp_a);
1878+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The minimum value must be less than the maximum value");
1879+
RETURN_FALSE;
1880+
}
1881+
1882+
INIT_GMP_RETVAL(gmpnum_result);
1883+
1884+
if (Z_LVAL_P(min_arg)) {
1885+
mpz_sub_ui(gmpnum_max, gmpnum_max, Z_LVAL_P(min_arg));
1886+
}
1887+
1888+
mpz_add_ui(gmpnum_max, gmpnum_max, 1);
1889+
mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_max);
1890+
1891+
if (Z_LVAL_P(min_arg)) {
1892+
mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
1893+
}
1894+
1895+
FREE_GMP_TEMP(temp_a);
1896+
1897+
}
1898+
else {
1899+
FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a);
1900+
1901+
if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
1902+
FREE_GMP_TEMP(temp_b);
1903+
FREE_GMP_TEMP(temp_a);
1904+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The minimum value must be less than the maximum value");
1905+
RETURN_FALSE;
1906+
}
1907+
1908+
INIT_GMP_RETVAL(gmpnum_result);
1909+
1910+
mpz_sub(gmpnum_max, gmpnum_max, gmpnum_min);
1911+
mpz_add_ui(gmpnum_max, gmpnum_max, 1);
1912+
mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_max);
1913+
mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
1914+
1915+
FREE_GMP_TEMP(temp_b);
1916+
FREE_GMP_TEMP(temp_a);
1917+
}
1918+
}
1919+
/* }}} */
1920+
18171921
/* {{{ proto GMP gmp_and(mixed a, mixed b)
18181922
Calculates logical AND of a and b */
18191923
ZEND_FUNCTION(gmp_and)

ext/gmp/php_gmp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ ZEND_FUNCTION(gmp_or);
6666
ZEND_FUNCTION(gmp_com);
6767
ZEND_FUNCTION(gmp_xor);
6868
ZEND_FUNCTION(gmp_random);
69+
ZEND_FUNCTION(gmp_random_bits);
70+
ZEND_FUNCTION(gmp_random_range);
6971
ZEND_FUNCTION(gmp_setbit);
7072
ZEND_FUNCTION(gmp_clrbit);
7173
ZEND_FUNCTION(gmp_scan0);

ext/gmp/tests/gmp_random_bits.phpt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--TEST--
2+
gmp_random_bits() basic tests
3+
--SKIPIF--
4+
<?php if (!extension_loaded("gmp")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
8+
var_dump(gmp_random_bits());
9+
var_dump(gmp_random_bits(0));
10+
var_dump(gmp_random_bits(-1));
11+
12+
// If these error the test fails.
13+
gmp_random_bits(1);
14+
gmp_random_bits(1024);
15+
16+
// 2 seconds to make sure the numbers stay in range
17+
$start = microtime(true);
18+
$limit = (2 ** 30) - 1;
19+
while (1) {
20+
for ($i = 0; $i < 5000; $i++) {
21+
$result = gmp_random_bits(30);
22+
if ($result < 0 || $result > $limit) {
23+
print "RANGE VIOLATION\n";
24+
var_dump($result);
25+
break 2;
26+
}
27+
}
28+
29+
if (microtime(true) - $start > 2) {
30+
break;
31+
}
32+
}
33+
34+
echo "Done\n";
35+
?>
36+
--EXPECTF--
37+
Warning: gmp_random_bits() expects exactly 1 parameter, 0 given in %s on line %d
38+
NULL
39+
40+
Warning: gmp_random_bits(): The number of bits must be positive in %s on line %d
41+
bool(false)
42+
43+
Warning: gmp_random_bits(): The number of bits must be positive in %s on line %d
44+
bool(false)
45+
Done

ext/gmp/tests/gmp_random_range.phpt

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
--TEST--
2+
gmp_random_range() basic tests
3+
--SKIPIF--
4+
<?php if (!extension_loaded("gmp")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
8+
$minusTen = gmp_init(-1);
9+
$plusTen = gmp_init(1);
10+
$zero = gmp_init(0);
11+
12+
var_dump(gmp_random_range());
13+
var_dump(gmp_random_range(10));
14+
var_dump(gmp_random_range(10, -10));
15+
16+
var_dump(gmp_random_range($plusTen, $minusTen));
17+
var_dump(gmp_random_range($plusTen, $zero));
18+
19+
// If these error the test fails.
20+
gmp_random_range(0, 10);
21+
gmp_random_range(1, 10);
22+
gmp_random_range(-1, 10);
23+
gmp_random_range(-10, 0);
24+
gmp_random_range(-10, -1);
25+
26+
gmp_random_range(0, $plusTen);
27+
gmp_random_range(1, $plusTen);
28+
gmp_random_range(-1, $plusTen);
29+
30+
gmp_random_range($zero, $plusTen);
31+
gmp_random_range($minusTen, $plusTen);
32+
33+
// 2 seconds to make sure the numbers stay in range
34+
$start = microtime(true);
35+
while (1) {
36+
for ($i = 0; $i < 5000; $i++) {
37+
$result = gmp_random_range(0, 1000);
38+
if ($result < 0 || $result > 1000) {
39+
print "RANGE VIOLATION 1\n";
40+
var_dump($result);
41+
break 2;
42+
}
43+
44+
$result = gmp_random_range(-1000, 0);
45+
if ($result < -1000 || $result > 0) {
46+
print "RANGE VIOLATION 2\n";
47+
var_dump($result);
48+
break 2;
49+
}
50+
51+
$result = gmp_random_range(-500, 500);
52+
if ($result < -500 || $result > 500) {
53+
print "RANGE VIOLATION 3\n";
54+
var_dump($result);
55+
break 2;
56+
}
57+
}
58+
59+
if (microtime(true) - $start > 2) {
60+
break;
61+
}
62+
}
63+
64+
echo "Done\n";
65+
?>
66+
--EXPECTF--
67+
Warning: gmp_random_range() expects exactly 2 parameters, 0 given in %s on line %d
68+
NULL
69+
70+
Warning: gmp_random_range() expects exactly 2 parameters, 1 given in %s on line %d
71+
NULL
72+
73+
Warning: gmp_random_range(): The minimum value must be less than the maximum value in %s on line %d
74+
bool(false)
75+
76+
Warning: gmp_random_range(): The minimum value must be less than the maximum value in %s on line %d
77+
bool(false)
78+
79+
Warning: gmp_random_range(): The minimum value must be less than the maximum value in %s on line %d
80+
bool(false)
81+
Done

0 commit comments

Comments
 (0)