summaryrefslogtreecommitdiff
path: root/ext/gmp
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2017-12-09 21:09:27 +0100
committerNikita Popov <nikita.ppv@gmail.com>2017-12-11 19:25:54 +0100
commit7fea79675cfb064726f3fc7845e2c2bb1f247ea5 (patch)
tree41adc67f230e213868e797351bcb9c2c1333e588 /ext/gmp
parentdc47171523b70112b14cf9144bdf223e9db550fe (diff)
downloadphp-git-7fea79675cfb064726f3fc7845e2c2bb1f247ea5.tar.gz
Add gmp_binomial()
Adds PHP bindings for mpz_bin_ui and mpz_bin_uiui, for calculating binomial coefficients.
Diffstat (limited to 'ext/gmp')
-rw-r--r--ext/gmp/gmp.c31
-rw-r--r--ext/gmp/php_gmp.h1
-rw-r--r--ext/gmp/tests/gmp_binomial.phpt67
3 files changed, 99 insertions, 0 deletions
diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index 4b4f7536f4..667df7cdad 100644
--- a/ext/gmp/gmp.c
+++ b/ext/gmp/gmp.c
@@ -188,6 +188,7 @@ const zend_function_entry gmp_functions[] = {
ZEND_FE(gmp_popcount, arginfo_gmp_unary)
ZEND_FE(gmp_hamdist, arginfo_gmp_binary)
ZEND_FE(gmp_nextprime, arginfo_gmp_unary)
+ ZEND_FE(gmp_binomial, arginfo_gmp_binary)
PHP_FE_END
};
/* }}} */
@@ -1382,6 +1383,36 @@ ZEND_FUNCTION(gmp_fact)
}
/* }}} */
+/* {{{ proto GMP gmp_binomial(mixed n, int k)
+ * Calculates binomial coefficient */
+ZEND_FUNCTION(gmp_binomial)
+{
+ zval *n_arg;
+ zend_long k;
+ mpz_ptr gmpnum_result;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &n_arg, &k) == FAILURE) {
+ return;
+ }
+
+ if (k < 0) {
+ php_error_docref(NULL, E_WARNING, "k cannot be negative");
+ RETURN_FALSE;
+ }
+
+ INIT_GMP_RETVAL(gmpnum_result);
+ if (Z_TYPE_P(n_arg) == IS_LONG && Z_LVAL_P(n_arg) >= 0) {
+ mpz_bin_uiui(gmpnum_result, (gmp_ulong) Z_LVAL_P(n_arg), (gmp_ulong) k);
+ } else {
+ mpz_ptr gmpnum_n;
+ gmp_temp_t temp_n;
+ FETCH_GMP_ZVAL(gmpnum_n, n_arg, temp_n);
+ mpz_bin_ui(gmpnum_result, gmpnum_n, (gmp_ulong) k);
+ FREE_GMP_TEMP(temp_n);
+ }
+}
+/* }}} */
+
/* {{{ proto GMP gmp_pow(mixed base, int exp)
Raise base to power exp */
ZEND_FUNCTION(gmp_pow)
diff --git a/ext/gmp/php_gmp.h b/ext/gmp/php_gmp.h
index 971d6593ec..8ba4b89d5b 100644
--- a/ext/gmp/php_gmp.h
+++ b/ext/gmp/php_gmp.h
@@ -78,6 +78,7 @@ ZEND_FUNCTION(gmp_testbit);
ZEND_FUNCTION(gmp_popcount);
ZEND_FUNCTION(gmp_hamdist);
ZEND_FUNCTION(gmp_nextprime);
+ZEND_FUNCTION(gmp_binomial);
ZEND_BEGIN_MODULE_GLOBALS(gmp)
zend_bool rand_initialized;
diff --git a/ext/gmp/tests/gmp_binomial.phpt b/ext/gmp/tests/gmp_binomial.phpt
new file mode 100644
index 0000000000..9c280c78df
--- /dev/null
+++ b/ext/gmp/tests/gmp_binomial.phpt
@@ -0,0 +1,67 @@
+--TEST--
+gmp_binomial(): Binomial coefficients
+--FILE--
+<?php
+
+var_dump(gmp_binomial(10, 5));
+var_dump(gmp_binomial("10", 5));
+$n = gmp_init(10);
+var_dump(gmp_binomial($n, 5));
+
+var_dump(gmp_binomial(10000, 100));
+
+var_dump(gmp_binomial(0, 0));
+var_dump(gmp_binomial(0, 1));
+var_dump(gmp_binomial(1, 0));
+var_dump(gmp_binomial(1, 1));
+
+var_dump(gmp_binomial(-1, 5)); // == -(1 + 5 - 1 over 5)
+var_dump(gmp_binomial(-2, 6)); // == (2 + 6 - 1 over 6)
+
+var_dump(gmp_binomial(5, -2));
+
+?>
+--EXPECTF--
+object(GMP)#1 (1) {
+ ["num"]=>
+ string(3) "252"
+}
+object(GMP)#1 (1) {
+ ["num"]=>
+ string(3) "252"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(3) "252"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(242) "65208469245472575695415972927215718683781335425416743372210247172869206520770178988927510291340552990847853030615947098118282371982392705479271195296127415562705948429404753632271959046657595132854990606768967505457396473467998111950929802400"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(1) "1"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(1) "0"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(1) "1"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(1) "1"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(2) "-1"
+}
+object(GMP)#2 (1) {
+ ["num"]=>
+ string(1) "7"
+}
+
+Warning: gmp_binomial(): k cannot be negative in %s on line %d
+bool(false)