2000-11-27 02:36:16 +08:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2001-12-11 23:32:16 +08:00
|
|
|
| PHP Version 4 |
|
2000-11-27 02:36:16 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2003-01-01 00:08:15 +08:00
|
|
|
| Copyright (c) 1997-2003 The PHP Group |
|
2000-11-27 02:36:16 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2003-06-11 04:04:29 +08:00
|
|
|
| This source file is subject to version 3.0 of the PHP license, |
|
2000-11-27 02:36:16 +08:00
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-11 04:04:29 +08:00
|
|
|
| available through the world-wide-web at the following url: |
|
|
|
|
| http://www.php.net/license/3_0.txt. |
|
2000-11-27 02:36:16 +08:00
|
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
|
|
+----------------------------------------------------------------------+
|
2002-02-28 16:29:35 +08:00
|
|
|
| Author: Stanislav Malyshev <stas@php.net> |
|
2000-11-27 02:36:16 +08:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
2001-05-24 18:07:29 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
#include "php.h"
|
|
|
|
#include "php_ini.h"
|
|
|
|
#include "php_gmp.h"
|
|
|
|
#include "ext/standard/info.h"
|
|
|
|
|
|
|
|
#if HAVE_GMP
|
|
|
|
|
|
|
|
#include <gmp.h>
|
|
|
|
/* If you declare any globals in php_gmp.h uncomment this:
|
|
|
|
ZEND_DECLARE_MODULE_GLOBALS(gmp)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* True global resources - no need for thread safety here */
|
|
|
|
static int le_gmp;
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_functions[]
|
|
|
|
*/
|
2000-11-27 02:36:16 +08:00
|
|
|
function_entry gmp_functions[] = {
|
|
|
|
ZEND_FE(gmp_init, NULL)
|
|
|
|
ZEND_FE(gmp_intval, NULL)
|
|
|
|
ZEND_FE(gmp_strval, NULL)
|
|
|
|
ZEND_FE(gmp_add, NULL)
|
|
|
|
ZEND_FE(gmp_sub, NULL)
|
|
|
|
ZEND_FE(gmp_mul, NULL)
|
|
|
|
ZEND_FE(gmp_div_qr, NULL)
|
|
|
|
ZEND_FE(gmp_div_q, NULL)
|
|
|
|
ZEND_FE(gmp_div_r, NULL)
|
|
|
|
ZEND_FALIAS(gmp_div, gmp_div_q, NULL)
|
|
|
|
ZEND_FE(gmp_mod, NULL)
|
|
|
|
ZEND_FE(gmp_divexact, NULL)
|
|
|
|
ZEND_FE(gmp_neg, NULL)
|
|
|
|
ZEND_FE(gmp_abs, NULL)
|
|
|
|
ZEND_FE(gmp_fact, NULL)
|
|
|
|
ZEND_FE(gmp_sqrt, NULL)
|
|
|
|
ZEND_FE(gmp_sqrtrem, NULL)
|
|
|
|
ZEND_FE(gmp_pow, NULL)
|
|
|
|
ZEND_FE(gmp_powm, NULL)
|
|
|
|
ZEND_FE(gmp_perfect_square, NULL)
|
|
|
|
ZEND_FE(gmp_prob_prime, NULL)
|
|
|
|
ZEND_FE(gmp_gcd, NULL)
|
|
|
|
ZEND_FE(gmp_gcdext, NULL)
|
|
|
|
ZEND_FE(gmp_invert, NULL)
|
|
|
|
ZEND_FE(gmp_jacobi, NULL)
|
|
|
|
ZEND_FE(gmp_legendre, NULL)
|
|
|
|
ZEND_FE(gmp_cmp, NULL)
|
|
|
|
ZEND_FE(gmp_sign, NULL)
|
|
|
|
ZEND_FE(gmp_random, NULL)
|
|
|
|
ZEND_FE(gmp_and, NULL)
|
|
|
|
ZEND_FE(gmp_or, NULL)
|
|
|
|
ZEND_FE(gmp_com, NULL)
|
|
|
|
ZEND_FE(gmp_xor, NULL)
|
2003-08-04 01:44:39 +08:00
|
|
|
ZEND_FE(gmp_setbit, first_arg_force_ref)
|
|
|
|
ZEND_FE(gmp_clrbit, first_arg_force_ref)
|
2000-11-29 23:49:18 +08:00
|
|
|
ZEND_FE(gmp_scan0, NULL)
|
|
|
|
ZEND_FE(gmp_scan1, NULL)
|
|
|
|
ZEND_FE(gmp_popcount, NULL)
|
|
|
|
ZEND_FE(gmp_hamdist, NULL)
|
2000-11-27 02:36:16 +08:00
|
|
|
{NULL, NULL, NULL} /* Must be the last line in gmp_functions[] */
|
|
|
|
};
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_module_entry
|
|
|
|
*/
|
2000-11-27 02:36:16 +08:00
|
|
|
zend_module_entry gmp_module_entry = {
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
STANDARD_MODULE_HEADER,
|
2000-11-27 02:36:16 +08:00
|
|
|
"gmp",
|
|
|
|
gmp_functions,
|
2001-08-11 10:46:57 +08:00
|
|
|
ZEND_MODULE_STARTUP_N(gmp),
|
|
|
|
ZEND_MODULE_SHUTDOWN_N(gmp),
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
NULL,
|
|
|
|
NULL,
|
2001-08-11 10:46:57 +08:00
|
|
|
ZEND_MODULE_INFO_N(gmp),
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
NO_VERSION_YET,
|
2000-11-27 02:36:16 +08:00
|
|
|
STANDARD_MODULE_PROPERTIES
|
|
|
|
};
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
#ifdef COMPILE_DL_GMP
|
|
|
|
ZEND_GET_MODULE(gmp)
|
2003-08-31 20:41:53 +08:00
|
|
|
# ifdef PHP_WIN32
|
|
|
|
# include "zend_arg_defs.c"
|
|
|
|
# endif
|
2000-11-27 02:36:16 +08:00
|
|
|
#endif
|
|
|
|
|
2001-07-31 13:44:11 +08:00
|
|
|
static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
#define GMP_RESOURCE_NAME "GMP integer"
|
|
|
|
|
|
|
|
#define GMP_ROUND_ZERO 0
|
|
|
|
#define GMP_ROUND_PLUSINF 1
|
|
|
|
#define GMP_ROUND_MINUSINF 2
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_emalloc
|
|
|
|
*/
|
2000-12-05 23:35:20 +08:00
|
|
|
static void *gmp_emalloc(size_t size)
|
|
|
|
{
|
|
|
|
return emalloc(size);
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-12-05 23:35:20 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_erealloc
|
|
|
|
*/
|
2000-12-05 23:35:20 +08:00
|
|
|
static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size)
|
|
|
|
{
|
|
|
|
return erealloc(ptr, new_size);
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-12-05 23:35:20 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_efree
|
|
|
|
*/
|
2000-12-05 23:35:20 +08:00
|
|
|
static void gmp_efree(void *ptr, size_t size)
|
|
|
|
{
|
|
|
|
efree(ptr);
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-12-05 23:35:20 +08:00
|
|
|
|
2001-06-07 01:52:03 +08:00
|
|
|
/* {{{ ZEND_MINIT_FUNCTION
|
2001-06-05 21:12:10 +08:00
|
|
|
*/
|
2001-08-11 10:46:57 +08:00
|
|
|
ZEND_MODULE_STARTUP_D(gmp)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
2001-08-08 01:57:55 +08:00
|
|
|
le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number);
|
2000-11-27 02:36:16 +08:00
|
|
|
REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
|
2000-12-05 23:35:20 +08:00
|
|
|
|
|
|
|
mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree);
|
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-07 01:52:03 +08:00
|
|
|
/* {{{ ZEND_MSHUTDOWN_FUNCTION
|
2001-06-05 21:12:10 +08:00
|
|
|
*/
|
2001-08-11 10:46:57 +08:00
|
|
|
ZEND_MODULE_SHUTDOWN_D(gmp)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-07 01:52:03 +08:00
|
|
|
/* {{{ ZEND_MINFO_FUNCTION
|
2001-06-05 21:12:10 +08:00
|
|
|
*/
|
2001-08-11 10:46:57 +08:00
|
|
|
ZEND_MODULE_INFO_D(gmp)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
|
|
|
php_info_print_table_start();
|
2002-06-09 20:56:27 +08:00
|
|
|
php_info_print_table_row(2, "gmp support", "enabled");
|
2000-11-27 02:36:16 +08:00
|
|
|
php_info_print_table_end();
|
|
|
|
|
|
|
|
/* Remove comments if you have entries in php.ini
|
|
|
|
DISPLAY_INI_ENTRIES();
|
|
|
|
*/
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
/* Fetch zval to be GMP number.
|
|
|
|
Initially, zval can be also number or string */
|
|
|
|
#define FETCH_GMP_ZVAL(gmpnumber, zval) \
|
|
|
|
if(Z_TYPE_PP(zval) == IS_RESOURCE) { \
|
|
|
|
ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp);\
|
|
|
|
} else {\
|
2003-01-25 00:29:40 +08:00
|
|
|
if(convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) {\
|
2000-11-29 23:49:18 +08:00
|
|
|
RETURN_FALSE;\
|
|
|
|
}\
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp);\
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create a new initialized GMP number */
|
|
|
|
#define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); }
|
|
|
|
#define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); }
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ convert_to_gmp
|
|
|
|
* Convert zval to be gmp number */
|
2003-01-25 00:29:40 +08:00
|
|
|
static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
|
|
|
int ret = 0;
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
int skip_lead = 0;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
*gmpnumber = emalloc(sizeof(mpz_t));
|
|
|
|
switch(Z_TYPE_PP(val)) {
|
|
|
|
case IS_LONG:
|
|
|
|
case IS_BOOL:
|
|
|
|
case IS_CONSTANT:
|
|
|
|
{
|
|
|
|
convert_to_long_ex(val);
|
|
|
|
mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case IS_STRING:
|
|
|
|
{
|
|
|
|
char *numstr = Z_STRVAL_PP(val);
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
|
|
|
|
if (Z_STRLEN_PP(val) > 2) {
|
|
|
|
if (numstr[0] == '0') {
|
|
|
|
if (numstr[1] == 'x' || numstr[1] == 'X') {
|
|
|
|
base = 16;
|
|
|
|
skip_lead = 1;
|
2002-02-11 07:19:38 +08:00
|
|
|
} else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) {
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
base = 2;
|
|
|
|
skip_lead = 1;
|
|
|
|
}
|
2001-08-05 22:48:17 +08:00
|
|
|
}
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2003-01-25 00:29:40 +08:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type");
|
2000-11-29 23:49:18 +08:00
|
|
|
efree(*gmpnumber);
|
2000-11-27 02:36:16 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
FREE_GMP_NUM(*gmpnumber);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
2000-11-27 02:36:16 +08:00
|
|
|
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
return SUCCESS;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ typedefs
|
|
|
|
*/
|
2000-11-27 02:36:16 +08:00
|
|
|
typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
|
2000-11-29 23:49:18 +08:00
|
|
|
typedef int (*gmp_unary_opl_t)(mpz_srcptr);
|
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long);
|
|
|
|
|
|
|
|
typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
|
2000-11-29 23:49:18 +08:00
|
|
|
typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
|
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long);
|
|
|
|
typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
|
|
|
|
typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long);
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
#define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0 TSRMLS_CC)
|
|
|
|
#define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0 TSRMLS_CC)
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop)
|
2000-11-27 02:36:16 +08:00
|
|
|
#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL)
|
2000-11-29 23:49:18 +08:00
|
|
|
#define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
/* Unary operations */
|
|
|
|
#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
|
2000-11-29 23:49:18 +08:00
|
|
|
#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
|
2000-11-27 02:36:16 +08:00
|
|
|
#define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_zval_binary_ui_op_ex
|
2000-11-27 02:36:16 +08:00
|
|
|
Execute GMP binary operation.
|
|
|
|
May return GMP resource or long if operation allows this
|
|
|
|
*/
|
2001-08-08 01:57:55 +08:00
|
|
|
static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return TSRMLS_DC)
|
|
|
|
{
|
2000-11-27 02:36:16 +08:00
|
|
|
mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
|
2001-08-08 01:57:55 +08:00
|
|
|
unsigned long long_result=0;
|
2000-11-27 02:36:16 +08:00
|
|
|
int use_ui=0;
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
if(gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
|
|
|
|
use_ui=1;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
if(use_ui && gmp_ui_op) {
|
|
|
|
if(allow_ui_return) {
|
|
|
|
long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
|
|
|
|
} else {
|
|
|
|
gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(use_ui && allow_ui_return) {
|
|
|
|
FREE_GMP_NUM(gmpnum_result);
|
|
|
|
RETURN_LONG((long)long_result);
|
|
|
|
} else {
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
}
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_zval_binary_ui_op2_ex
|
2000-11-27 02:36:16 +08:00
|
|
|
Execute GMP binary operation which returns 2 values.
|
|
|
|
May return GMP resources or longs if operation allows this.
|
|
|
|
*/
|
2001-08-08 01:57:55 +08:00
|
|
|
static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return TSRMLS_DC)
|
|
|
|
{
|
2000-11-27 02:36:16 +08:00
|
|
|
mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2;
|
|
|
|
zval r;
|
|
|
|
int use_ui=0;
|
2003-10-13 19:46:36 +08:00
|
|
|
unsigned long long_result = 0;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
if(gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) {
|
|
|
|
/* use _ui function */
|
|
|
|
use_ui=1;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result1);
|
|
|
|
INIT_GMP_NUM(gmpnum_result2);
|
|
|
|
|
|
|
|
if(use_ui && gmp_ui_op) {
|
|
|
|
if(allow_ui_return) {
|
|
|
|
long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
|
|
|
|
} else {
|
|
|
|
gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
array_init(return_value);
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
|
|
|
|
add_index_resource(return_value, 0, Z_LVAL(r));
|
|
|
|
if(use_ui && allow_ui_return) {
|
|
|
|
mpz_clear(*gmpnum_result2);
|
|
|
|
add_index_long(return_value, 1, long_result);
|
|
|
|
} else {
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
|
|
|
|
add_index_resource(return_value, 1, Z_LVAL(r));
|
|
|
|
}
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ _gmp_binary_ui_op
|
|
|
|
*/
|
2000-11-27 02:36:16 +08:00
|
|
|
static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op) {
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
/* Unary operations */
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_zval_unary_op
|
|
|
|
*/
|
2001-08-08 01:57:55 +08:00
|
|
|
static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC)
|
|
|
|
{
|
2000-11-27 02:36:16 +08:00
|
|
|
mpz_t *gmpnum_a, *gmpnum_result;
|
2001-08-08 01:57:55 +08:00
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
gmp_op(*gmpnum_result, *gmpnum_a);
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_zval_unary_ui_op
|
|
|
|
*/
|
2000-11-27 02:36:16 +08:00
|
|
|
static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op) {
|
|
|
|
mpz_t *gmpnum_result;
|
|
|
|
|
|
|
|
convert_to_long_ex(a_arg);
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg));
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ _gmp_unary_ui_op
|
2000-11-27 02:36:16 +08:00
|
|
|
Execute GMP unary operation.
|
|
|
|
*/
|
|
|
|
static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op) {
|
|
|
|
zval **a_arg;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_unary_ui_op(return_value, a_arg, gmp_op);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ _gmp_unary_op
|
|
|
|
*/
|
2000-11-27 02:36:16 +08:00
|
|
|
static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op) {
|
|
|
|
zval **a_arg;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ _gmp_unary_opl
|
|
|
|
*/
|
2000-11-29 23:49:18 +08:00
|
|
|
static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op) {
|
|
|
|
zval **a_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(gmp_op(*gmpnum_a));
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ _gmp_binary_opl
|
|
|
|
*/
|
2000-11-29 23:49:18 +08:00
|
|
|
static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op) {
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_b;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, a_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(gmp_op(*gmpnum_a, *gmpnum_b));
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-08-05 22:48:17 +08:00
|
|
|
/* {{{ proto resource gmp_init(mixed number [, int base])
|
2000-12-01 23:25:22 +08:00
|
|
|
Initializes GMP number */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_init)
|
|
|
|
{
|
2001-08-05 22:48:17 +08:00
|
|
|
zval **number_arg, **base_arg;
|
2000-11-27 02:36:16 +08:00
|
|
|
mpz_t * gmpnumber;
|
2001-08-05 22:48:17 +08:00
|
|
|
int argc;
|
|
|
|
int base=0;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2001-08-05 22:48:17 +08:00
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &number_arg, &base_arg) == FAILURE){
|
2000-11-27 02:36:16 +08:00
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
2001-08-05 22:48:17 +08:00
|
|
|
if (argc==2) {
|
|
|
|
convert_to_long_ex(base_arg);
|
|
|
|
base = Z_LVAL_PP(base_arg);
|
|
|
|
if(base < 2 || base > 36) {
|
2003-01-25 00:29:40 +08:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %d (should be between 2 and 36)", base);
|
2001-08-05 22:48:17 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-01-25 00:29:40 +08:00
|
|
|
if(convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) {
|
2000-11-27 02:36:16 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write your own code here to handle argument number. */
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int gmp_intval(resource gmpnumber)
|
2000-12-01 23:25:22 +08:00
|
|
|
Gets signed long value of GMP number */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_intval)
|
|
|
|
{
|
|
|
|
zval **gmpnumber_arg;
|
|
|
|
mpz_t * gmpnum;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &gmpnumber_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) {
|
|
|
|
ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp);
|
|
|
|
RETVAL_LONG(mpz_get_si(*gmpnum));
|
|
|
|
} else {
|
|
|
|
convert_to_long_ex(gmpnumber_arg);
|
|
|
|
RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto string gmp_strval(resource gmpnumber [, int base])
|
2000-12-01 23:25:22 +08:00
|
|
|
Gets string representation of GMP number */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_strval)
|
|
|
|
{
|
|
|
|
zval **gmpnumber_arg, **base_arg;
|
2001-08-08 01:57:55 +08:00
|
|
|
int base=10, num_len, argc;
|
2000-11-27 02:36:16 +08:00
|
|
|
mpz_t * gmpnum;
|
|
|
|
char *out_string;
|
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &gmpnumber_arg, &base_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg);
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 2:
|
|
|
|
convert_to_long_ex(base_arg);
|
|
|
|
base = Z_LVAL_PP(base_arg);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
base = 10;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2000-12-05 22:17:38 +08:00
|
|
|
if(base < 2 || base > 36) {
|
2003-01-25 00:29:40 +08:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %d", base);
|
2000-12-05 22:17:38 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
num_len = mpz_sizeinbase(*gmpnum, base);
|
|
|
|
out_string = emalloc(num_len+2);
|
|
|
|
if(mpz_sgn(*gmpnum) < 0) {
|
|
|
|
num_len++;
|
|
|
|
}
|
|
|
|
mpz_get_str(out_string, base, *gmpnum);
|
Fix for bugs #10133 and #15454.
Bug #15454 results from a bug in GMP. If you pass in a string '0xABCD' and
specify a base of 0, GMP figures out that it is hex and skips over the 0x
characters. If you specify base 16, then it doesn't skip those chars.
This was confirmed with the following test program:
#include <stdio.h>
#include <gmp.h>
int main()
{
char *str_one, *str_two;
mpz_t num_one, num_two;
mpz_init_set_str (num_one, "0x45", 0);
str_one = mpz_get_str(NULL, 10, num_one);
mpz_init_set_str (num_two, "0x45", 16);
str_two = mpz_get_str(NULL, 10, num_two);
printf("%s / %s\n", str_one, str_two);
mpz_clear (num_one);
mpz_clear (num_two);
return 0;
}
We now take anything that starts with 0[xX] as hexidecimal and anything
that starts 0[bB] as binary (this is what GMP does internally). We also
no longer force the base to 10 or 16, but instead let GMP decide what the
best base is, be it hex, dec, or octal.
2002-02-11 07:12:57 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
From GMP documentation for mpz_sizeinbase():
|
|
|
|
The returned value will be exact or 1 too big. If base is a power of
|
|
|
|
2, the returned value will always be exact.
|
|
|
|
|
|
|
|
So let's check to see if we already have a \0 byte...
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (out_string[num_len-1] == '\0')
|
|
|
|
num_len--;
|
|
|
|
else
|
|
|
|
out_string[num_len] = '\0';
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
RETVAL_STRINGL(out_string, num_len, 0);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_add(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Add a and b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_add)
|
|
|
|
{
|
|
|
|
gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_sub(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Subtract b from a */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_sub)
|
|
|
|
{
|
|
|
|
gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_mul(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Multiply a and b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_mul)
|
|
|
|
{
|
|
|
|
gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto array gmp_div_qr(resource a, resource b [, int round])
|
2000-12-01 23:25:22 +08:00
|
|
|
Divide a by b, returns quotient and reminder */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_div_qr)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg, **round_arg;
|
2001-08-08 01:57:55 +08:00
|
|
|
int round=GMP_ROUND_ZERO, argc;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &a_arg, &b_arg, &round_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 3:
|
|
|
|
convert_to_long_ex(round_arg);
|
|
|
|
round = Z_LVAL_PP(round_arg);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
round = GMP_ROUND_ZERO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(round) {
|
|
|
|
case GMP_ROUND_ZERO:
|
|
|
|
gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui);
|
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
|
|
|
gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui);
|
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
|
|
|
gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
/* {{{ proto resource gmp_div_r(resource a, resource b [, int round])
|
2000-12-01 23:25:22 +08:00
|
|
|
Divide a by b, returns reminder only */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_div_r)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg, **round_arg;
|
2001-08-08 01:57:55 +08:00
|
|
|
int round=GMP_ROUND_ZERO, argc;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &a_arg, &b_arg, &round_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 3:
|
|
|
|
convert_to_long_ex(round_arg);
|
|
|
|
round = Z_LVAL_PP(round_arg);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
round = GMP_ROUND_ZERO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(round) {
|
|
|
|
case GMP_ROUND_ZERO:
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1 TSRMLS_CC);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1 TSRMLS_CC);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1 TSRMLS_CC);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
/* {{{ proto resource gmp_div_q(resource a, resource b [, int round])
|
2000-12-01 23:25:22 +08:00
|
|
|
Divide a by b, returns quotient only */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_div_q)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg, **round_arg;
|
2001-08-08 01:57:55 +08:00
|
|
|
int round=GMP_ROUND_ZERO, argc;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &a_arg, &b_arg, &round_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 3:
|
|
|
|
convert_to_long_ex(round_arg);
|
|
|
|
round = Z_LVAL_PP(round_arg);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
round = GMP_ROUND_ZERO;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(round) {
|
|
|
|
case GMP_ROUND_ZERO:
|
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui);
|
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui);
|
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_mod(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Computes a modulo b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_mod)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui, 1 TSRMLS_CC);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_divexact(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Divide a by b using exact division algorithm */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_divexact)
|
|
|
|
{
|
|
|
|
gmp_binary_op(mpz_divexact);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_neg(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Negates a number */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_neg)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_neg);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_abs(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates absolute value */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_abs)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_abs);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_fact(int a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates factorial function */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_fact)
|
|
|
|
{
|
|
|
|
gmp_unary_ui_op(mpz_fac_ui);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-05 22:47:40 +08:00
|
|
|
/* {{{ proto resource gmp_pow(resource base, int exp)
|
2000-12-01 23:25:22 +08:00
|
|
|
Raise base to power exp */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_pow)
|
|
|
|
{
|
|
|
|
zval **base_arg, **exp_arg;
|
|
|
|
mpz_t *gmpnum_result, *gmpnum_base;
|
|
|
|
int use_ui=0;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &base_arg, &exp_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) {
|
|
|
|
use_ui=1;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_base, base_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
convert_to_long_ex(exp_arg);
|
|
|
|
|
|
|
|
if(Z_LVAL_PP(exp_arg) < 0) {
|
2003-01-25 00:29:40 +08:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,"Negative exponent not supported");
|
2000-11-27 02:36:16 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
if(use_ui) {
|
|
|
|
mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), Z_LVAL_PP(exp_arg));
|
|
|
|
} else {
|
|
|
|
mpz_pow_ui(*gmpnum_result, *gmpnum_base, Z_LVAL_PP(exp_arg));
|
|
|
|
}
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_powm(resource base, resource exp, resource mod)
|
2000-12-01 23:25:22 +08:00
|
|
|
Raise base to power exp and take result modulo mod */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_powm)
|
|
|
|
{
|
|
|
|
zval **base_arg, **exp_arg, **mod_arg;
|
|
|
|
mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result;
|
|
|
|
int use_ui=0;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &base_arg, &exp_arg, &mod_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_base, base_arg);
|
|
|
|
if(Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) {
|
|
|
|
use_ui=1;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_exp, exp_arg);
|
|
|
|
}
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_mod, mod_arg);
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
if(use_ui) {
|
|
|
|
mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod);
|
|
|
|
} else {
|
|
|
|
mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod);
|
|
|
|
}
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_sqrt(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Takes integer part of square root of a */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_sqrt)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_sqrt);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto array gmp_sqrtrem(resource a)
|
2001-12-15 22:23:07 +08:00
|
|
|
Square root with remainder */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_sqrtrem)
|
|
|
|
{
|
|
|
|
zval **a_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2;
|
|
|
|
zval r;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result1);
|
|
|
|
INIT_GMP_NUM(gmpnum_result2);
|
|
|
|
|
|
|
|
mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a);
|
|
|
|
|
|
|
|
array_init(return_value);
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp);
|
|
|
|
add_index_resource(return_value, 0, Z_LVAL(r));
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp);
|
|
|
|
add_index_resource(return_value, 1, Z_LVAL(r));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto bool gmp_perfect_square(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Checks if a is an exact square */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_perfect_square)
|
|
|
|
{
|
|
|
|
zval **a_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
RETURN_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0));
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
/* {{{ proto int gmp_prob_prime(resource a[, int reps])
|
|
|
|
Checks if a is "probably prime" */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_prob_prime)
|
|
|
|
{
|
|
|
|
zval **gmpnumber_arg, **reps_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
2001-08-08 01:57:55 +08:00
|
|
|
int argc, reps=10;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &gmpnumber_arg, &reps_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg);
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 2:
|
|
|
|
convert_to_long_ex(reps_arg);
|
|
|
|
reps = Z_LVAL_PP(reps_arg);
|
|
|
|
break;
|
|
|
|
case 1:
|
2000-12-06 22:10:40 +08:00
|
|
|
reps = 10;
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
RETURN_LONG(mpz_probab_prime_p(*gmpnum_a, reps));
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_gcd(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Computes greatest common denominator (gcd) of a and b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_gcd)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
2001-08-12 00:39:07 +08:00
|
|
|
gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui, 1 TSRMLS_CC);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto array gmp_gcdext(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_gcdext)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g;
|
|
|
|
zval r;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
2003-03-14 00:10:21 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_g);
|
|
|
|
INIT_GMP_NUM(gmpnum_s);
|
|
|
|
INIT_GMP_NUM(gmpnum_t);
|
|
|
|
|
|
|
|
mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b);
|
|
|
|
|
|
|
|
array_init(return_value);
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp);
|
|
|
|
add_assoc_resource(return_value, "g", Z_LVAL(r));
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp);
|
|
|
|
add_assoc_resource(return_value, "s", Z_LVAL(r));
|
|
|
|
ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp);
|
|
|
|
add_assoc_resource(return_value, "t", Z_LVAL(r));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_invert(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Computes the inverse of a modulo b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_invert)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
2002-04-10 04:18:09 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
2001-08-12 00:39:07 +08:00
|
|
|
if(mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b)) {
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
} else {
|
|
|
|
FREE_GMP_NUM(gmpnum_result);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
/* {{{ proto int gmp_jacobi(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Computes Jacobi symbol */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_jacobi)
|
|
|
|
{
|
2000-11-29 23:49:18 +08:00
|
|
|
gmp_binary_opl(mpz_jacobi);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-06 22:10:40 +08:00
|
|
|
/* {{{ proto int gmp_legendre(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Computes Legendre symbol */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_legendre)
|
|
|
|
{
|
2000-11-29 23:49:18 +08:00
|
|
|
gmp_binary_opl(mpz_legendre);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int gmp_cmp(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Compares two numbers */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_cmp)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_b;
|
|
|
|
int use_si=0, res;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
|
|
|
if(Z_TYPE_PP(b_arg) == IS_LONG) {
|
|
|
|
use_si=1;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(use_si) {
|
|
|
|
res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg));
|
|
|
|
} else {
|
|
|
|
res = mpz_cmp(*gmpnum_a, *gmpnum_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_LONG(res);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int gmp_sign(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Gets the sign of the number */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_sign)
|
|
|
|
{
|
|
|
|
zval **a_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(mpz_sgn(*gmpnum_a));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_random([int limiter])
|
2000-12-01 23:25:22 +08:00
|
|
|
Gets random number */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_random)
|
|
|
|
{
|
|
|
|
zval **limiter_arg;
|
|
|
|
int limiter, argc;
|
|
|
|
mpz_t *gmpnum_result;
|
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
|
|
|
|
2003-11-18 18:28:13 +08:00
|
|
|
if (argc == 0) {
|
|
|
|
limiter = 20;
|
|
|
|
} else if (argc == 1 && zend_get_parameters_ex(1, &limiter_arg) == SUCCESS) {
|
2000-11-27 02:36:16 +08:00
|
|
|
convert_to_long_ex(limiter_arg);
|
|
|
|
limiter = Z_LVAL_PP(limiter_arg);
|
|
|
|
} else {
|
2003-11-18 18:28:13 +08:00
|
|
|
WRONG_PARAM_COUNT;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
mpz_random(*gmpnum_result, limiter);
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_and(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates logical AND of a and b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_and)
|
|
|
|
{
|
|
|
|
gmp_binary_op(mpz_and);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_or(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates logical OR of a and b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_or)
|
|
|
|
{
|
|
|
|
gmp_binary_op(mpz_ior);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-12-05 22:47:40 +08:00
|
|
|
/* {{{ proto resource gmp_com(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates one's complement of a */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_com)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_com);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto resource gmp_xor(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates logical exclusive OR of a and b */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_xor)
|
|
|
|
{
|
|
|
|
/* use formula: a^b = (a|b)&^(a&b) */
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
|
|
|
|
|
|
|
INIT_GMP_NUM(gmpnum_result);
|
|
|
|
INIT_GMP_NUM(gmpnum_t);
|
|
|
|
|
|
|
|
mpz_and(*gmpnum_t, *gmpnum_a, *gmpnum_b);
|
|
|
|
mpz_com(*gmpnum_t, *gmpnum_t);
|
|
|
|
|
|
|
|
mpz_ior(*gmpnum_result, *gmpnum_a, *gmpnum_b);
|
|
|
|
mpz_and(*gmpnum_result, *gmpnum_result, *gmpnum_t);
|
|
|
|
|
|
|
|
FREE_GMP_NUM(gmpnum_t);
|
|
|
|
|
|
|
|
ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void gmp_setbit(resource &a, int index[, bool set_clear])
|
2000-12-01 23:25:22 +08:00
|
|
|
Sets or clear bit in a */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_setbit)
|
|
|
|
{
|
2002-03-28 07:47:06 +08:00
|
|
|
zval **a_arg, **ind_arg, **set_c_arg;
|
2001-08-08 01:57:55 +08:00
|
|
|
int argc, index, set=1;
|
2000-11-27 02:36:16 +08:00
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
argc = ZEND_NUM_ARGS();
|
2002-03-28 07:47:06 +08:00
|
|
|
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &a_arg, &ind_arg, &set_c_arg) == FAILURE){
|
2000-11-27 02:36:16 +08:00
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
|
|
|
|
|
|
|
|
convert_to_long_ex(ind_arg);
|
|
|
|
index = Z_LVAL_PP(ind_arg);
|
|
|
|
|
|
|
|
switch (argc) {
|
|
|
|
case 3:
|
2002-03-28 07:47:06 +08:00
|
|
|
convert_to_long_ex(set_c_arg);
|
|
|
|
set = Z_LVAL_PP(set_c_arg);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
set = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(set) {
|
|
|
|
mpz_setbit(*gmpnum_a, index);
|
|
|
|
} else {
|
|
|
|
mpz_clrbit(*gmpnum_a, index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto void gmp_clrbit(resource &a, int index)
|
2000-12-01 23:25:22 +08:00
|
|
|
Clears bit in a */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_clrbit)
|
|
|
|
{
|
|
|
|
zval **a_arg, **ind_arg;
|
|
|
|
int index;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &ind_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp);
|
|
|
|
|
|
|
|
convert_to_long_ex(ind_arg);
|
|
|
|
index = Z_LVAL_PP(ind_arg);
|
|
|
|
|
|
|
|
mpz_clrbit(*gmpnum_a, index);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2000-11-29 23:49:18 +08:00
|
|
|
/* {{{ proto int gmp_popcount(resource a)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates the population count of a */
|
2000-11-29 23:49:18 +08:00
|
|
|
ZEND_FUNCTION(gmp_popcount)
|
|
|
|
{
|
|
|
|
zval **a_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &a_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(mpz_popcount(*gmpnum_a));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int gmp_hamdist(resource a, resource b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Calculates hamming distance between a and b */
|
2000-11-29 23:49:18 +08:00
|
|
|
ZEND_FUNCTION(gmp_hamdist)
|
|
|
|
{
|
|
|
|
zval **a_arg, **b_arg;
|
|
|
|
mpz_t *gmpnum_a, *gmpnum_b;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(1, &a_arg, &b_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_b, b_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int gmp_scan0(resource a, int start)
|
2000-12-01 23:25:22 +08:00
|
|
|
Finds first zero bit */
|
2000-11-29 23:49:18 +08:00
|
|
|
ZEND_FUNCTION(gmp_scan0)
|
|
|
|
{
|
|
|
|
zval **a_arg, **start_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &start_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
convert_to_long_ex(start_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(mpz_scan0(*gmpnum_a, Z_LVAL_PP(start_arg)));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto int gmp_scan1(resource a, int start)
|
2000-12-01 23:25:22 +08:00
|
|
|
Finds first non-zero bit */
|
2000-11-29 23:49:18 +08:00
|
|
|
ZEND_FUNCTION(gmp_scan1)
|
|
|
|
{
|
|
|
|
zval **a_arg, **start_arg;
|
|
|
|
mpz_t *gmpnum_a;
|
|
|
|
|
|
|
|
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &a_arg, &start_arg) == FAILURE){
|
|
|
|
WRONG_PARAM_COUNT;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg);
|
|
|
|
convert_to_long_ex(start_arg);
|
|
|
|
|
|
|
|
RETURN_LONG(mpz_scan1(*gmpnum_a, Z_LVAL_PP(start_arg)));
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ _php_gmpnum_free
|
|
|
|
*/
|
2001-07-31 13:44:11 +08:00
|
|
|
static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
|
|
|
mpz_t *gmpnum = (mpz_t *)rsrc->ptr;
|
2001-07-31 13:44:11 +08:00
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
FREE_GMP_NUM(gmpnum);
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
#endif /* HAVE_GMP */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
2001-09-09 21:29:31 +08:00
|
|
|
* vim600: sw=4 ts=4 fdm=marker
|
|
|
|
* vim<600: sw=4 ts=4
|
2000-11-27 02:36:16 +08:00
|
|
|
*/
|