diff options
author | Ondřej Surý <ondrej@sury.org> | 2014-11-18 20:30:43 +0100 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2014-11-18 20:30:43 +0100 |
commit | f40f1ce174885cd0f526c003eca3fa523e0ef269 (patch) | |
tree | ce22a7abe1212824c0be6bace0eb49de7249f9f9 /ext/gmp | |
parent | 1dc5de7731d1bc41002f9b58f798e93f393e6f08 (diff) | |
download | php-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.c | 148 | ||||
-rw-r--r-- | ext/gmp/php_gmp.h | 2 | ||||
-rw-r--r-- | ext/gmp/tests/gmp_random_bits.phpt | 45 | ||||
-rw-r--r-- | ext/gmp/tests/gmp_random_range.phpt | 81 |
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 |