]> granicus.if.org Git - php/commitdiff
Add gmp_binomial()
authorNikita Popov <nikita.ppv@gmail.com>
Sat, 9 Dec 2017 20:09:27 +0000 (21:09 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 11 Dec 2017 18:25:54 +0000 (19:25 +0100)
Adds PHP bindings for mpz_bin_ui and mpz_bin_uiui, for calculating
binomial coefficients.

NEWS
UPGRADING
ext/gmp/gmp.c
ext/gmp/php_gmp.h
ext/gmp/tests/gmp_binomial.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 1611c51ccc98615371534e5072143c00b421b904..cde7a3656d6fd2a53616cef469962a85da11fc2d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -48,6 +48,7 @@ PHP                                                                        NEWS
 
 - GMP:
   . Export internal structures and accessor helpers for GMP object. (Sara)
+  . Added gmp_binomial(n, k). (Nikita)
 
 - intl:
   . Fixed bug #75317 (UConverter::setDestinationEncoding changes source instead 
index b2ad92add021f39d344cd524688dc79690c52417..a68d3180741c4a4ab94ca100b7b689cbc7cfc17d 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -85,6 +85,9 @@ Date:
   . Added the DateTime::createFromImmutable() method, which mirrors
     DateTimeImmutable::createFromMutable().
 
+GMP:
+  . Added gmp_binomial(n, k) for calculating binomial coefficients.
+
 Intl:
   . Added void Spoofchecker::setRestrictionLevel(int $level) method, available
     when linked with ICU >= 58.1. Levels are represented as class constants
index 4b4f7536f44ce20ec07dda922bc65203799947be..667df7cdad40d7aac82bdc5df17d90532b6953e6 100644 (file)
@@ -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)
index 971d6593eca52b17fded96c3e811dc23aeefd08a..8ba4b89d5b6ab3168ec94ff8f48fe2e150aec066 100644 (file)
@@ -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 (file)
index 0000000..9c280c7
--- /dev/null
@@ -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)