summaryrefslogtreecommitdiff
path: root/ext/gmp
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2014-11-18 20:30:43 +0100
committerOndřej Surý <ondrej@sury.org>2014-11-18 20:30:43 +0100
commitf40f1ce174885cd0f526c003eca3fa523e0ef269 (patch)
treece22a7abe1212824c0be6bace0eb49de7249f9f9 /ext/gmp
parent1dc5de7731d1bc41002f9b58f798e93f393e6f08 (diff)
downloadphp-f40f1ce174885cd0f526c003eca3fa523e0ef269.tar.gz
New upstream version 5.6.3+dfsgupstream/5.6.3+dfsg
Diffstat (limited to 'ext/gmp')
-rw-r--r--ext/gmp/gmp.c148
-rw-r--r--ext/gmp/php_gmp.h2
-rw-r--r--ext/gmp/tests/gmp_random_bits.phpt45
-rw-r--r--ext/gmp/tests/gmp_random_range.phpt81
4 files changed, 241 insertions, 35 deletions
diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index bad610c0b..e9c1ad341 100644
--- a/ext/gmp/gmp.c
+++ b/ext/gmp/gmp.c
@@ -104,6 +104,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0)
ZEND_ARG_INFO(0, limiter)
ZEND_END_ARG_INFO()
+ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_bits, 0, 0, 1)
+ ZEND_ARG_INFO(0, bits)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_range, 0, 0, 2)
+ ZEND_ARG_INFO(0, min)
+ ZEND_ARG_INFO(0, max)
+ZEND_END_ARG_INFO()
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
ZEND_ARG_INFO(0, a)
ZEND_ARG_INFO(0, index)
@@ -161,6 +170,8 @@ const zend_function_entry gmp_functions[] = {
ZEND_FE(gmp_cmp, arginfo_gmp_binary)
ZEND_FE(gmp_sign, arginfo_gmp_unary)
ZEND_FE(gmp_random, arginfo_gmp_random)
+ ZEND_FE(gmp_random_bits, arginfo_gmp_random_bits)
+ ZEND_FE(gmp_random_range, arginfo_gmp_random_range)
ZEND_FE(gmp_and, arginfo_gmp_binary)
ZEND_FE(gmp_or, arginfo_gmp_binary)
ZEND_FE(gmp_com, arginfo_gmp_unary)
@@ -352,30 +363,6 @@ static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_una
#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
#define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
-/* {{{ gmp_emalloc
- */
-static void *gmp_emalloc(size_t size)
-{
- return emalloc(size);
-}
-/* }}} */
-
-/* {{{ gmp_erealloc
- */
-static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size)
-{
- return erealloc(ptr, new_size);
-}
-/* }}} */
-
-/* {{{ gmp_efree
- */
-static void gmp_efree(void *ptr, size_t size)
-{
- efree(ptr);
-}
-/* }}} */
-
static inline long gmp_get_long(zval *zv) /* {{{ */
{
if (Z_TYPE_P(zv) == IS_LONG) {
@@ -723,8 +710,6 @@ ZEND_MINIT_FUNCTION(gmp)
REGISTER_LONG_CONSTANT("GMP_BIG_ENDIAN", GMP_BIG_ENDIAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("GMP_NATIVE_ENDIAN", GMP_NATIVE_ENDIAN, CONST_CS | CONST_PERSISTENT);
- mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree);
-
return SUCCESS;
}
/* }}} */
@@ -1784,6 +1769,22 @@ ZEND_FUNCTION(gmp_sign)
}
/* }}} */
+static void gmp_init_random(TSRMLS_D)
+{
+ if (!GMPG(rand_initialized)) {
+ /* Initialize */
+#if GMP_42_OR_NEWER
+ gmp_randinit_mt(GMPG(rand_state));
+#else
+ gmp_randinit_lc_2exp(GMPG(rand_state), 32L);
+#endif
+ /* Seed */
+ gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
+
+ GMPG(rand_initialized) = 1;
+ }
+}
+
/* {{{ proto GMP gmp_random([int limiter])
Gets random number */
ZEND_FUNCTION(gmp_random)
@@ -1796,16 +1797,8 @@ ZEND_FUNCTION(gmp_random)
}
INIT_GMP_RETVAL(gmpnum_result);
+ gmp_init_random(TSRMLS_C);
- if (!GMPG(rand_initialized)) {
- /* Initialize */
- gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L);
-
- /* Seed */
- gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
-
- GMPG(rand_initialized) = 1;
- }
#ifdef GMP_LIMB_BITS
mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
#else
@@ -1814,6 +1807,91 @@ ZEND_FUNCTION(gmp_random)
}
/* }}} */
+/* {{{ proto GMP gmp_random_bits(int bits)
+ Gets a random number in the range 0 to (2 ** n) - 1 */
+ZEND_FUNCTION(gmp_random_bits)
+{
+ long bits;
+ mpz_ptr gmpnum_result;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &bits) == FAILURE) {
+ return;
+ }
+
+ if (bits <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The number of bits must be positive");
+ RETURN_FALSE;
+ }
+
+ INIT_GMP_RETVAL(gmpnum_result);
+ gmp_init_random(TSRMLS_C);
+
+ mpz_urandomb(gmpnum_result, GMPG(rand_state), bits);
+}
+/* }}} */
+
+/* {{{ proto GMP gmp_random_range(mixed min, mixed max)
+ Gets a random number in the range min to max */
+ZEND_FUNCTION(gmp_random_range)
+{
+ zval *min_arg, *max_arg;
+ mpz_ptr gmpnum_min, gmpnum_max, gmpnum_result;
+ gmp_temp_t temp_a, temp_b;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &min_arg, &max_arg) == FAILURE) {
+ return;
+ }
+
+ gmp_init_random(TSRMLS_C);
+
+ FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a);
+
+ if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
+ if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
+ FREE_GMP_TEMP(temp_a);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The minimum value must be less than the maximum value");
+ RETURN_FALSE;
+ }
+
+ INIT_GMP_RETVAL(gmpnum_result);
+
+ if (Z_LVAL_P(min_arg)) {
+ mpz_sub_ui(gmpnum_max, gmpnum_max, Z_LVAL_P(min_arg));
+ }
+
+ mpz_add_ui(gmpnum_max, gmpnum_max, 1);
+ mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_max);
+
+ if (Z_LVAL_P(min_arg)) {
+ mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
+ }
+
+ FREE_GMP_TEMP(temp_a);
+
+ }
+ else {
+ FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a);
+
+ if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
+ FREE_GMP_TEMP(temp_b);
+ FREE_GMP_TEMP(temp_a);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The minimum value must be less than the maximum value");
+ RETURN_FALSE;
+ }
+
+ INIT_GMP_RETVAL(gmpnum_result);
+
+ mpz_sub(gmpnum_max, gmpnum_max, gmpnum_min);
+ mpz_add_ui(gmpnum_max, gmpnum_max, 1);
+ mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_max);
+ mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
+
+ FREE_GMP_TEMP(temp_b);
+ FREE_GMP_TEMP(temp_a);
+ }
+}
+/* }}} */
+
/* {{{ proto GMP gmp_and(mixed a, mixed b)
Calculates logical AND of a and b */
ZEND_FUNCTION(gmp_and)
diff --git a/ext/gmp/php_gmp.h b/ext/gmp/php_gmp.h
index b3706c534..a1a1dc262 100644
--- a/ext/gmp/php_gmp.h
+++ b/ext/gmp/php_gmp.h
@@ -66,6 +66,8 @@ ZEND_FUNCTION(gmp_or);
ZEND_FUNCTION(gmp_com);
ZEND_FUNCTION(gmp_xor);
ZEND_FUNCTION(gmp_random);
+ZEND_FUNCTION(gmp_random_bits);
+ZEND_FUNCTION(gmp_random_range);
ZEND_FUNCTION(gmp_setbit);
ZEND_FUNCTION(gmp_clrbit);
ZEND_FUNCTION(gmp_scan0);
diff --git a/ext/gmp/tests/gmp_random_bits.phpt b/ext/gmp/tests/gmp_random_bits.phpt
new file mode 100644
index 000000000..21d493cdb
--- /dev/null
+++ b/ext/gmp/tests/gmp_random_bits.phpt
@@ -0,0 +1,45 @@
+--TEST--
+gmp_random_bits() basic tests
+--SKIPIF--
+<?php if (!extension_loaded("gmp")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(gmp_random_bits());
+var_dump(gmp_random_bits(0));
+var_dump(gmp_random_bits(-1));
+
+// If these error the test fails.
+gmp_random_bits(1);
+gmp_random_bits(1024);
+
+// 2 seconds to make sure the numbers stay in range
+$start = microtime(true);
+$limit = (2 ** 30) - 1;
+while (1) {
+ for ($i = 0; $i < 5000; $i++) {
+ $result = gmp_random_bits(30);
+ if ($result < 0 || $result > $limit) {
+ print "RANGE VIOLATION\n";
+ var_dump($result);
+ break 2;
+ }
+ }
+
+ if (microtime(true) - $start > 2) {
+ break;
+ }
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Warning: gmp_random_bits() expects exactly 1 parameter, 0 given in %s on line %d
+NULL
+
+Warning: gmp_random_bits(): The number of bits must be positive in %s on line %d
+bool(false)
+
+Warning: gmp_random_bits(): The number of bits must be positive in %s on line %d
+bool(false)
+Done
diff --git a/ext/gmp/tests/gmp_random_range.phpt b/ext/gmp/tests/gmp_random_range.phpt
new file mode 100644
index 000000000..a8e7c4a9c
--- /dev/null
+++ b/ext/gmp/tests/gmp_random_range.phpt
@@ -0,0 +1,81 @@
+--TEST--
+gmp_random_range() basic tests
+--SKIPIF--
+<?php if (!extension_loaded("gmp")) print "skip"; ?>
+--FILE--
+<?php
+
+$minusTen = gmp_init(-1);
+$plusTen = gmp_init(1);
+$zero = gmp_init(0);
+
+var_dump(gmp_random_range());
+var_dump(gmp_random_range(10));
+var_dump(gmp_random_range(10, -10));
+
+var_dump(gmp_random_range($plusTen, $minusTen));
+var_dump(gmp_random_range($plusTen, $zero));
+
+// If these error the test fails.
+gmp_random_range(0, 10);
+gmp_random_range(1, 10);
+gmp_random_range(-1, 10);
+gmp_random_range(-10, 0);
+gmp_random_range(-10, -1);
+
+gmp_random_range(0, $plusTen);
+gmp_random_range(1, $plusTen);
+gmp_random_range(-1, $plusTen);
+
+gmp_random_range($zero, $plusTen);
+gmp_random_range($minusTen, $plusTen);
+
+// 2 seconds to make sure the numbers stay in range
+$start = microtime(true);
+while (1) {
+ for ($i = 0; $i < 5000; $i++) {
+ $result = gmp_random_range(0, 1000);
+ if ($result < 0 || $result > 1000) {
+ print "RANGE VIOLATION 1\n";
+ var_dump($result);
+ break 2;
+ }
+
+ $result = gmp_random_range(-1000, 0);
+ if ($result < -1000 || $result > 0) {
+ print "RANGE VIOLATION 2\n";
+ var_dump($result);
+ break 2;
+ }
+
+ $result = gmp_random_range(-500, 500);
+ if ($result < -500 || $result > 500) {
+ print "RANGE VIOLATION 3\n";
+ var_dump($result);
+ break 2;
+ }
+ }
+
+ if (microtime(true) - $start > 2) {
+ break;
+ }
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+Warning: gmp_random_range() expects exactly 2 parameters, 0 given in %s on line %d
+NULL
+
+Warning: gmp_random_range() expects exactly 2 parameters, 1 given in %s on line %d
+NULL
+
+Warning: gmp_random_range(): The minimum value must be less than the maximum value in %s on line %d
+bool(false)
+
+Warning: gmp_random_range(): The minimum value must be less than the maximum value in %s on line %d
+bool(false)
+
+Warning: gmp_random_range(): The minimum value must be less than the maximum value in %s on line %d
+bool(false)
+Done