2000-11-26 18:36:16 +00:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2004-01-08 08:18:22 +00:00
|
|
|
| PHP Version 5 |
|
2000-11-26 18:36:16 +00:00
|
|
|
+----------------------------------------------------------------------+
|
2014-01-03 03:08:10 +00:00
|
|
|
| Copyright (c) 1997-2014 The PHP Group |
|
2000-11-26 18:36:16 +00:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 12:51:34 +00:00
|
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
2000-11-26 18:36:16 +00:00
|
|
|
| that is bundled with this package in the file LICENSE, and is |
|
2003-06-10 20:04:29 +00:00
|
|
|
| available through the world-wide-web at the following url: |
|
2006-01-01 12:51:34 +00:00
|
|
|
| http://www.php.net/license/3_01.txt |
|
2000-11-26 18:36:16 +00: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 08:29:35 +00:00
|
|
|
| Author: Stanislav Malyshev <stas@php.net> |
|
2000-11-26 18:36:16 +00:00
|
|
|
+----------------------------------------------------------------------+
|
|
|
|
*/
|
|
|
|
|
2001-05-24 10:07:29 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
2000-11-26 18:36:16 +00:00
|
|
|
#include "php.h"
|
|
|
|
#include "php_ini.h"
|
|
|
|
#include "php_gmp.h"
|
|
|
|
#include "ext/standard/info.h"
|
2013-10-29 19:58:30 +00:00
|
|
|
#include "ext/standard/php_var.h"
|
|
|
|
#include "ext/standard/php_smart_str_public.h"
|
2013-06-17 15:49:24 +00:00
|
|
|
#include "zend_exceptions.h"
|
2000-11-26 18:36:16 +00:00
|
|
|
|
|
|
|
#if HAVE_GMP
|
|
|
|
|
|
|
|
#include <gmp.h>
|
2003-11-19 04:44:06 +00:00
|
|
|
|
|
|
|
/* Needed for gmp_random() */
|
|
|
|
#include "ext/standard/php_rand.h"
|
|
|
|
#include "ext/standard/php_lcg.h"
|
|
|
|
#define GMP_ABS(x) ((x) >= 0 ? (x) : -(x))
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2006-06-14 21:36:10 +00:00
|
|
|
/* {{{ arginfo */
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, number)
|
|
|
|
ZEND_ARG_INFO(0, base)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_intval, 0, 0, 1)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, gmpnumber)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_strval, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, gmpnumber)
|
|
|
|
ZEND_ARG_INFO(0, base)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_unary, 0, 0, 1)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_binary, 0, 0, 2)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, b)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div, 0, 0, 2)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, b)
|
|
|
|
ZEND_ARG_INFO(0, round)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_pow, 0, 0, 2)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, base)
|
|
|
|
ZEND_ARG_INFO(0, exp)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_powm, 0, 0, 3)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, base)
|
|
|
|
ZEND_ARG_INFO(0, exp)
|
|
|
|
ZEND_ARG_INFO(0, mod)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_root, 0, 0, 2)
|
2013-11-28 22:42:23 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, nth)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, reps)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
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_setbit, 0, 0, 2)
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, index)
|
|
|
|
ZEND_ARG_INFO(0, set_clear)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_bit, 0, 0, 2)
|
2007-11-01 17:51:34 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, index)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_scan, 0, 0, 2)
|
2006-06-14 21:36:10 +00:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, start)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
/* }}} */
|
|
|
|
|
2006-06-15 18:33:09 +00:00
|
|
|
ZEND_DECLARE_MODULE_GLOBALS(gmp)
|
|
|
|
static ZEND_GINIT_FUNCTION(gmp);
|
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_functions[]
|
|
|
|
*/
|
2007-09-27 18:00:48 +00:00
|
|
|
const zend_function_entry gmp_functions[] = {
|
2013-11-28 23:00:41 +00:00
|
|
|
ZEND_FE(gmp_init, arginfo_gmp_init)
|
|
|
|
ZEND_FE(gmp_intval, arginfo_gmp_intval)
|
|
|
|
ZEND_FE(gmp_strval, arginfo_gmp_strval)
|
|
|
|
ZEND_FE(gmp_add, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_sub, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_mul, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_div_qr, arginfo_gmp_div)
|
|
|
|
ZEND_FE(gmp_div_q, arginfo_gmp_div)
|
|
|
|
ZEND_FE(gmp_div_r, arginfo_gmp_div)
|
|
|
|
ZEND_FALIAS(gmp_div, gmp_div_q, arginfo_gmp_div)
|
|
|
|
ZEND_FE(gmp_mod, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_divexact, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_neg, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_abs, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_fact, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_sqrt, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_sqrtrem, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_root, arginfo_gmp_root)
|
|
|
|
ZEND_FE(gmp_rootrem, arginfo_gmp_root)
|
|
|
|
ZEND_FE(gmp_pow, arginfo_gmp_pow)
|
|
|
|
ZEND_FE(gmp_powm, arginfo_gmp_powm)
|
|
|
|
ZEND_FE(gmp_perfect_square, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime)
|
|
|
|
ZEND_FE(gmp_gcd, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_gcdext, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_invert, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_jacobi, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_legendre, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_cmp, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_sign, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_random, arginfo_gmp_random)
|
|
|
|
ZEND_FE(gmp_and, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_or, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_com, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_xor, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_setbit, arginfo_gmp_setbit)
|
|
|
|
ZEND_FE(gmp_clrbit, arginfo_gmp_bit)
|
|
|
|
ZEND_FE(gmp_testbit, arginfo_gmp_bit)
|
|
|
|
ZEND_FE(gmp_scan0, arginfo_gmp_scan)
|
|
|
|
ZEND_FE(gmp_scan1, arginfo_gmp_scan)
|
|
|
|
ZEND_FE(gmp_popcount, arginfo_gmp_unary)
|
|
|
|
ZEND_FE(gmp_hamdist, arginfo_gmp_binary)
|
|
|
|
ZEND_FE(gmp_nextprime, arginfo_gmp_unary)
|
2011-07-25 11:35:02 +00:00
|
|
|
PHP_FE_END
|
2000-11-26 18:36:16 +00:00
|
|
|
};
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_module_entry
|
|
|
|
*/
|
2000-11-26 18:36:16 +00: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-10 23:12:57 +00:00
|
|
|
STANDARD_MODULE_HEADER,
|
2000-11-26 18:36:16 +00:00
|
|
|
"gmp",
|
|
|
|
gmp_functions,
|
2001-08-11 02:46:57 +00:00
|
|
|
ZEND_MODULE_STARTUP_N(gmp),
|
2007-01-12 12:32:15 +00:00
|
|
|
NULL,
|
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-10 23:12:57 +00:00
|
|
|
NULL,
|
2003-11-19 04:44:06 +00:00
|
|
|
ZEND_MODULE_DEACTIVATE_N(gmp),
|
2001-08-11 02:46:57 +00: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-10 23:12:57 +00:00
|
|
|
NO_VERSION_YET,
|
2006-06-15 18:33:09 +00:00
|
|
|
ZEND_MODULE_GLOBALS(gmp),
|
|
|
|
ZEND_GINIT(gmp),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
STANDARD_MODULE_PROPERTIES_EX
|
2000-11-26 18:36:16 +00:00
|
|
|
};
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
|
|
|
#ifdef COMPILE_DL_GMP
|
|
|
|
ZEND_GET_MODULE(gmp)
|
|
|
|
#endif
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
zend_class_entry *gmp_ce;
|
|
|
|
static zend_object_handlers gmp_object_handlers;
|
|
|
|
|
|
|
|
typedef struct _gmp_object {
|
|
|
|
mpz_t num;
|
2014-05-06 16:44:28 +00:00
|
|
|
zend_object std;
|
2013-06-17 15:49:24 +00:00
|
|
|
} gmp_object;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
typedef struct _gmp_temp {
|
|
|
|
mpz_t num;
|
|
|
|
zend_bool is_used;
|
|
|
|
} gmp_temp_t;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
|
|
|
#define GMP_ROUND_ZERO 0
|
|
|
|
#define GMP_ROUND_PLUSINF 1
|
|
|
|
#define GMP_ROUND_MINUSINF 2
|
|
|
|
|
2013-12-02 19:10:08 +00:00
|
|
|
#define GMP_42_OR_NEWER \
|
|
|
|
((__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2))
|
|
|
|
|
2010-09-15 10:51:55 +00:00
|
|
|
/* The maximum base for input and output conversions is 62 from GMP 4.2
|
|
|
|
* onwards. */
|
2013-12-02 19:10:08 +00:00
|
|
|
#if GMP_42_OR_NEWER
|
2010-09-15 10:51:55 +00:00
|
|
|
# define MAX_BASE 62
|
|
|
|
#else
|
|
|
|
# define MAX_BASE 36
|
|
|
|
#endif
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
#define IS_GMP(zval) \
|
|
|
|
(Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce TSRMLS_CC))
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
#define GET_GMP_OBJECT_FROM_OBJ(obj) \
|
|
|
|
((gmp_object *) ((char *) (obj) - XtOffsetOf(gmp_object, std)))
|
|
|
|
#define GET_GMP_OBJECT_FROM_ZVAL(zv) \
|
|
|
|
GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zv))
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
#define GET_GMP_FROM_ZVAL(zval) \
|
2014-05-06 16:44:28 +00:00
|
|
|
GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
/* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number
|
|
|
|
* (mpz_ptr) from a zval. If the zval is not a GMP instance, then we
|
|
|
|
* try to convert the value to a temporary gmp number using convert_to_gmp.
|
|
|
|
* This temporary number is stored in the temp argument, which is of type
|
|
|
|
* gmp_temp_t. This temporary value needs to be freed lateron using the
|
|
|
|
* FREE_GMP_TEMP macro.
|
|
|
|
*
|
|
|
|
* If the conversion to a gmp number fails, the macros return false.
|
|
|
|
* The _DEP / _DEP_DEP variants additionally free the temporary values
|
|
|
|
* passed in the last / last two arguments.
|
|
|
|
*
|
|
|
|
* If one zval can sometimes be fetched as a long you have to set the
|
|
|
|
* is_used member of the corresponding gmp_temp_t value to 0, otherwise
|
|
|
|
* the FREE_GMP_TEMP and *_DEP macros will not work properly.
|
|
|
|
*
|
|
|
|
* The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code
|
|
|
|
* as I couldn't find a way to combine them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define FREE_GMP_TEMP(temp) \
|
|
|
|
if (temp.is_used) { \
|
|
|
|
mpz_clear(temp.num); \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \
|
|
|
|
if (IS_GMP(zval)) { \
|
|
|
|
gmpnumber = GET_GMP_FROM_ZVAL(zval); \
|
|
|
|
temp.is_used = 0; \
|
|
|
|
} else { \
|
|
|
|
mpz_init(temp.num); \
|
|
|
|
if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \
|
|
|
|
mpz_clear(temp.num); \
|
|
|
|
FREE_GMP_TEMP(dep1); \
|
|
|
|
FREE_GMP_TEMP(dep2); \
|
|
|
|
RETURN_FALSE; \
|
|
|
|
} \
|
|
|
|
temp.is_used = 1; \
|
|
|
|
gmpnumber = temp.num; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \
|
|
|
|
if (IS_GMP(zval)) { \
|
|
|
|
gmpnumber = GET_GMP_FROM_ZVAL(zval); \
|
|
|
|
temp.is_used = 0; \
|
|
|
|
} else { \
|
|
|
|
mpz_init(temp.num); \
|
|
|
|
if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \
|
|
|
|
mpz_clear(temp.num); \
|
|
|
|
FREE_GMP_TEMP(dep); \
|
|
|
|
RETURN_FALSE; \
|
|
|
|
} \
|
|
|
|
temp.is_used = 1; \
|
|
|
|
gmpnumber = temp.num; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \
|
|
|
|
if (IS_GMP(zval)) { \
|
|
|
|
gmpnumber = GET_GMP_FROM_ZVAL(zval); \
|
|
|
|
temp.is_used = 0; \
|
|
|
|
} else { \
|
|
|
|
mpz_init(temp.num); \
|
|
|
|
if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \
|
|
|
|
mpz_clear(temp.num); \
|
|
|
|
RETURN_FALSE; \
|
|
|
|
} \
|
|
|
|
temp.is_used = 1; \
|
|
|
|
gmpnumber = temp.num; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INIT_GMP_RETVAL(gmpnumber) \
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_create(return_value, &gmpnumber TSRMLS_CC)
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
static void gmp_strval(zval *result, mpz_t gmpnum, long base);
|
|
|
|
static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC);
|
|
|
|
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The gmp_*_op functions provide an implementation for several common types
|
|
|
|
* of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually
|
|
|
|
* passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already
|
|
|
|
* include parameter parsing.
|
|
|
|
*/
|
|
|
|
typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
|
|
|
|
typedef int (*gmp_unary_opl_t)(mpz_srcptr);
|
|
|
|
|
|
|
|
typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long);
|
|
|
|
|
|
|
|
typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
|
|
|
|
typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
|
|
|
|
|
|
|
|
typedef void (*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 void (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long);
|
|
|
|
|
|
|
|
static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC);
|
|
|
|
static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC);
|
|
|
|
static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC);
|
|
|
|
static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC);
|
|
|
|
|
|
|
|
/* Binary operations */
|
|
|
|
#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0)
|
|
|
|
#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0)
|
|
|
|
#define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
|
|
|
|
#define gmp_binary_ui_op_no_zero(op, uop) \
|
|
|
|
_gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1)
|
|
|
|
|
|
|
|
/* Unary operations */
|
|
|
|
#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
|
|
|
|
#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)
|
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_emalloc
|
|
|
|
*/
|
2000-12-05 15:35:20 +00:00
|
|
|
static void *gmp_emalloc(size_t size)
|
|
|
|
{
|
|
|
|
return emalloc(size);
|
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-12-05 15:35:20 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_erealloc
|
|
|
|
*/
|
2000-12-05 15:35:20 +00:00
|
|
|
static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size)
|
|
|
|
{
|
|
|
|
return erealloc(ptr, new_size);
|
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-12-05 15:35:20 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_efree
|
|
|
|
*/
|
2000-12-05 15:35:20 +00:00
|
|
|
static void gmp_efree(void *ptr, size_t size)
|
|
|
|
{
|
|
|
|
efree(ptr);
|
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-12-05 15:35:20 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
static void gmp_free_object_storage(zend_object *obj TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj);
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
mpz_clear(intern->num);
|
|
|
|
zend_object_std_dtor(&intern->std TSRMLS_CC);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
static inline zend_object *gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_object *intern = emalloc(sizeof(gmp_object)
|
|
|
|
+ sizeof(zval) * (ce->default_properties_count - 1));
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
zend_object_std_init(&intern->std, ce TSRMLS_CC);
|
|
|
|
object_properties_init(&intern->std, ce);
|
|
|
|
|
|
|
|
mpz_init(intern->num);
|
|
|
|
*gmpnum_target = intern->num;
|
2014-05-06 16:44:28 +00:00
|
|
|
intern->std.handlers = &gmp_object_handlers;
|
2013-06-17 15:49:24 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
return &intern->std;
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
static zend_object *gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
|
|
|
mpz_ptr gmpnum_dummy;
|
|
|
|
return gmp_create_object_ex(ce, &gmpnum_dummy TSRMLS_CC);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
static inline void gmp_create(zval *target, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
2014-05-06 16:44:28 +00:00
|
|
|
ZVAL_OBJ(target, gmp_create_object_ex(gmp_ce, gmpnum_target TSRMLS_CC));
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
static int gmp_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */
|
|
|
|
{
|
|
|
|
mpz_ptr gmpnum;
|
|
|
|
switch (type) {
|
|
|
|
case IS_STRING:
|
|
|
|
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
|
|
|
gmp_strval(writeobj, gmpnum, 10);
|
|
|
|
return SUCCESS;
|
|
|
|
case IS_LONG:
|
|
|
|
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
|
|
|
ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
|
|
|
|
return SUCCESS;
|
|
|
|
case IS_DOUBLE:
|
|
|
|
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
|
|
|
ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
|
|
|
|
return SUCCESS;
|
|
|
|
default:
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-10-29 19:58:30 +00:00
|
|
|
static HashTable *gmp_get_debug_info(zval *obj, int *is_temp TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
2013-10-29 19:58:30 +00:00
|
|
|
HashTable *ht, *props = zend_std_get_properties(obj TSRMLS_CC);
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(obj);
|
2014-05-06 16:44:28 +00:00
|
|
|
zval zv;
|
2013-06-17 15:49:24 +00:00
|
|
|
|
2013-10-29 19:58:30 +00:00
|
|
|
*is_temp = 1;
|
|
|
|
ALLOC_HASHTABLE(ht);
|
2014-05-23 16:37:53 +00:00
|
|
|
zend_array_dup(ht, props);
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_strval(&zv, gmpnum, 10);
|
|
|
|
zend_hash_str_update(ht, "num", sizeof("num")-1, &zv);
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
return ht;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
static zend_object *gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_object *old_object = GET_GMP_OBJECT_FROM_ZVAL(obj);
|
|
|
|
gmp_object *new_object = GET_GMP_OBJECT_FROM_OBJ(gmp_create_object(Z_OBJCE_P(obj) TSRMLS_CC));
|
2013-06-17 15:49:24 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
zend_objects_clone_members( &new_object->std, &old_object->std TSRMLS_CC);
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
mpz_set(new_object->num, old_object->num);
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
return &new_object->std;
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2 TSRMLS_DC) {
|
2014-05-06 16:44:28 +00:00
|
|
|
long shift = zval_get_long(op2);
|
2013-06-17 15:49:24 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
if (shift < 0) {
|
2013-06-17 15:49:24 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shift cannot be negative");
|
|
|
|
RETVAL_FALSE;
|
|
|
|
} else {
|
|
|
|
mpz_ptr gmpnum_op, gmpnum_result;
|
|
|
|
gmp_temp_t temp;
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_op, op1, temp);
|
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-05-06 16:44:28 +00:00
|
|
|
op(gmpnum_result, gmpnum_op, (unsigned long) shift);
|
2013-06-17 15:49:24 +00:00
|
|
|
FREE_GMP_TEMP(temp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
|
|
|
|
gmp_zval_binary_ui_op( \
|
|
|
|
result, op1, op2, op, (gmp_binary_ui_op_t) uop, \
|
|
|
|
check_b_zero TSRMLS_CC \
|
|
|
|
); \
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0)
|
|
|
|
#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0)
|
|
|
|
|
|
|
|
#define DO_UNARY_OP(op) \
|
|
|
|
gmp_zval_unary_op(result, op1, op TSRMLS_CC); \
|
|
|
|
return SUCCESS;
|
|
|
|
|
|
|
|
static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
|
|
|
|
{
|
|
|
|
switch (opcode) {
|
|
|
|
case ZEND_ADD:
|
|
|
|
DO_BINARY_UI_OP(mpz_add);
|
|
|
|
case ZEND_SUB:
|
|
|
|
DO_BINARY_UI_OP(mpz_sub);
|
|
|
|
case ZEND_MUL:
|
|
|
|
DO_BINARY_UI_OP(mpz_mul);
|
2013-11-19 07:36:06 +00:00
|
|
|
case ZEND_POW:
|
|
|
|
shift_operator_helper(mpz_pow_ui, result, op1, op2 TSRMLS_CC);
|
|
|
|
return SUCCESS;
|
2013-06-17 15:49:24 +00:00
|
|
|
case ZEND_DIV:
|
|
|
|
DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1);
|
|
|
|
case ZEND_MOD:
|
|
|
|
DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1);
|
|
|
|
case ZEND_SL:
|
|
|
|
shift_operator_helper(mpz_mul_2exp, result, op1, op2 TSRMLS_CC);
|
|
|
|
return SUCCESS;
|
|
|
|
case ZEND_SR:
|
|
|
|
shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2 TSRMLS_CC);
|
|
|
|
return SUCCESS;
|
|
|
|
case ZEND_BW_OR:
|
|
|
|
DO_BINARY_OP(mpz_ior);
|
|
|
|
case ZEND_BW_AND:
|
|
|
|
DO_BINARY_OP(mpz_and);
|
|
|
|
case ZEND_BW_XOR:
|
|
|
|
DO_BINARY_OP(mpz_xor);
|
|
|
|
case ZEND_BW_NOT:
|
|
|
|
DO_UNARY_OP(mpz_com);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
|
|
|
|
{
|
|
|
|
gmp_cmp(result, op1, op2 TSRMLS_CC);
|
2014-05-06 16:44:28 +00:00
|
|
|
if (Z_TYPE_P(result) == IS_FALSE) {
|
2013-06-17 15:49:24 +00:00
|
|
|
ZVAL_LONG(result, 1);
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-23 23:43:12 +00:00
|
|
|
static int gmp_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC) /* {{{ */
|
2013-06-17 15:49:24 +00:00
|
|
|
{
|
2013-11-23 23:43:12 +00:00
|
|
|
mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(object);
|
2013-10-29 19:58:30 +00:00
|
|
|
smart_str buf = {0};
|
2014-05-06 16:44:28 +00:00
|
|
|
zval zv;
|
2014-04-28 08:01:54 +00:00
|
|
|
php_serialize_data_t serialize_data = (php_serialize_data_t) data;
|
2014-05-06 16:44:28 +00:00
|
|
|
zend_array tmp_arr;
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2014-04-28 08:01:54 +00:00
|
|
|
PHP_VAR_SERIALIZE_INIT(serialize_data);
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_strval(&zv, gmpnum, 10);
|
|
|
|
php_var_serialize(&buf, &zv, &serialize_data TSRMLS_CC);
|
|
|
|
zval_dtor(&zv);
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
ZVAL_ARR(&zv, &tmp_arr);
|
|
|
|
tmp_arr.ht = *zend_std_get_properties(object TSRMLS_CC);
|
|
|
|
php_var_serialize(&buf, &zv, &serialize_data TSRMLS_CC);
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2014-04-28 08:01:54 +00:00
|
|
|
PHP_VAR_SERIALIZE_DESTROY(serialize_data);
|
2014-05-06 16:44:28 +00:00
|
|
|
*buffer = (unsigned char *) estrndup(buf.s->val, buf.s->len);
|
|
|
|
*buf_len = buf.s->len;
|
|
|
|
STR_RELEASE(buf.s);
|
2013-11-23 23:43:12 +00:00
|
|
|
|
|
|
|
return SUCCESS;
|
2013-10-29 19:58:30 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC) /* {{{ */
|
2013-10-29 19:58:30 +00:00
|
|
|
{
|
2013-11-23 23:43:12 +00:00
|
|
|
mpz_ptr gmpnum;
|
2013-10-29 19:58:30 +00:00
|
|
|
const unsigned char *p, *max;
|
2014-05-06 16:44:28 +00:00
|
|
|
zval zv;
|
2013-11-23 23:43:12 +00:00
|
|
|
int retval = FAILURE;
|
2014-04-28 08:01:54 +00:00
|
|
|
php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2014-05-13 08:57:42 +00:00
|
|
|
ZVAL_UNDEF(&zv);
|
2014-04-28 08:01:54 +00:00
|
|
|
PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_create(object, &gmpnum TSRMLS_CC);
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2013-11-23 23:43:12 +00:00
|
|
|
p = buf;
|
|
|
|
max = buf + buf_len;
|
2013-10-29 19:58:30 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
if (!php_var_unserialize(&zv, &p, max, &unserialize_data TSRMLS_CC)
|
|
|
|
|| Z_TYPE(zv) != IS_STRING
|
|
|
|
|| convert_to_gmp(gmpnum, &zv, 10 TSRMLS_CC) == FAILURE
|
2013-06-17 15:49:24 +00:00
|
|
|
) {
|
2013-10-29 19:58:30 +00:00
|
|
|
zend_throw_exception(NULL, "Could not unserialize number", 0 TSRMLS_CC);
|
|
|
|
goto exit;
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
2013-10-29 19:58:30 +00:00
|
|
|
zval_dtor(&zv);
|
2014-05-13 08:57:42 +00:00
|
|
|
ZVAL_UNDEF(&zv);
|
2013-06-17 15:49:24 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
if (!php_var_unserialize(&zv, &p, max, &unserialize_data TSRMLS_CC)
|
|
|
|
|| Z_TYPE(zv) != IS_ARRAY
|
2013-10-29 19:58:30 +00:00
|
|
|
) {
|
|
|
|
zend_throw_exception(NULL, "Could not unserialize properties", 0 TSRMLS_CC);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
if (zend_hash_num_elements(Z_ARRVAL(zv)) != 0) {
|
2013-10-29 19:58:30 +00:00
|
|
|
zend_hash_copy(
|
2014-05-06 16:44:28 +00:00
|
|
|
zend_std_get_properties(object TSRMLS_CC), Z_ARRVAL(zv),
|
|
|
|
(copy_ctor_func_t) zval_add_ref
|
2013-10-29 19:58:30 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-11-23 23:43:12 +00:00
|
|
|
retval = SUCCESS;
|
2013-10-29 19:58:30 +00:00
|
|
|
exit:
|
|
|
|
zval_dtor(&zv);
|
2014-04-28 08:01:54 +00:00
|
|
|
PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
|
2013-11-23 23:43:12 +00:00
|
|
|
return retval;
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2006-06-15 18:33:09 +00:00
|
|
|
/* {{{ ZEND_GINIT_FUNCTION
|
2003-11-19 04:44:06 +00:00
|
|
|
*/
|
2006-06-15 18:33:09 +00:00
|
|
|
static ZEND_GINIT_FUNCTION(gmp)
|
2003-11-19 04:44:06 +00:00
|
|
|
{
|
|
|
|
gmp_globals->rand_initialized = 0;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2001-06-06 17:52:03 +00:00
|
|
|
/* {{{ ZEND_MINIT_FUNCTION
|
2001-06-05 13:12:10 +00:00
|
|
|
*/
|
2013-06-17 15:49:24 +00:00
|
|
|
ZEND_MINIT_FUNCTION(gmp)
|
2000-11-26 18:36:16 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zend_class_entry tmp_ce;
|
2013-11-23 23:43:12 +00:00
|
|
|
INIT_CLASS_ENTRY(tmp_ce, "GMP", NULL);
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_ce = zend_register_internal_class(&tmp_ce TSRMLS_CC);
|
|
|
|
gmp_ce->create_object = gmp_create_object;
|
2013-11-23 23:43:12 +00:00
|
|
|
gmp_ce->serialize = gmp_serialize;
|
|
|
|
gmp_ce->unserialize = gmp_unserialize;
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
memcpy(&gmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_object_handlers.offset = XtOffsetOf(gmp_object, std);
|
|
|
|
gmp_object_handlers.free_obj = gmp_free_object_storage;
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_object_handlers.cast_object = gmp_cast_object;
|
2013-10-29 19:58:30 +00:00
|
|
|
gmp_object_handlers.get_debug_info = gmp_get_debug_info;
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_object_handlers.clone_obj = gmp_clone_obj;
|
|
|
|
gmp_object_handlers.do_operation = gmp_do_operation;
|
|
|
|
gmp_object_handlers.compare = gmp_compare;
|
|
|
|
|
2000-11-26 18:36:16 +00: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);
|
2009-12-10 02:25:47 +00:00
|
|
|
#ifdef mpir_version
|
|
|
|
REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
|
|
|
|
#endif
|
2007-04-26 13:44:02 +00:00
|
|
|
REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
|
2000-12-05 15:35:20 +00:00
|
|
|
|
|
|
|
mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree);
|
|
|
|
|
2000-11-26 18:36:16 +00:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2003-11-19 04:44:06 +00:00
|
|
|
/* {{{ ZEND_RSHUTDOWN_FUNCTION
|
|
|
|
*/
|
|
|
|
ZEND_MODULE_DEACTIVATE_D(gmp)
|
|
|
|
{
|
|
|
|
if (GMPG(rand_initialized)) {
|
|
|
|
gmp_randclear(GMPG(rand_state));
|
|
|
|
GMPG(rand_initialized) = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2001-06-06 17:52:03 +00:00
|
|
|
/* {{{ ZEND_MINFO_FUNCTION
|
2001-06-05 13:12:10 +00:00
|
|
|
*/
|
2001-08-11 02:46:57 +00:00
|
|
|
ZEND_MODULE_INFO_D(gmp)
|
2000-11-26 18:36:16 +00:00
|
|
|
{
|
|
|
|
php_info_print_table_start();
|
2002-06-09 12:56:27 +00:00
|
|
|
php_info_print_table_row(2, "gmp support", "enabled");
|
2009-12-10 02:25:47 +00:00
|
|
|
#ifdef mpir_version
|
|
|
|
php_info_print_table_row(2, "MPIR version", mpir_version);
|
|
|
|
#else
|
2007-04-26 13:44:02 +00:00
|
|
|
php_info_print_table_row(2, "GMP version", gmp_version);
|
2009-12-10 02:25:47 +00:00
|
|
|
#endif
|
2000-11-26 18:36:16 +00:00
|
|
|
php_info_print_table_end();
|
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ convert_to_gmp
|
|
|
|
* Convert zval to be gmp number */
|
2013-06-17 15:49:24 +00:00
|
|
|
static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC)
|
2000-11-26 18:36:16 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
switch (Z_TYPE_P(val)) {
|
2000-11-26 18:36:16 +00:00
|
|
|
case IS_LONG:
|
2014-05-06 16:44:28 +00:00
|
|
|
case IS_FALSE:
|
|
|
|
case IS_TRUE: {
|
|
|
|
mpz_set_si(gmpnumber, zval_get_long(val));
|
2013-06-17 15:49:24 +00:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
case IS_STRING: {
|
|
|
|
char *numstr = Z_STRVAL_P(val);
|
|
|
|
int skip_lead = 0;
|
2013-12-30 13:37:32 +00:00
|
|
|
int ret;
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
if (Z_STRLEN_P(val) > 2) {
|
|
|
|
if (numstr[0] == '0') {
|
|
|
|
if (numstr[1] == 'x' || numstr[1] == 'X') {
|
|
|
|
base = 16;
|
|
|
|
skip_lead = 1;
|
|
|
|
} else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) {
|
|
|
|
base = 2;
|
|
|
|
skip_lead = 1;
|
2001-08-05 14:48:17 +00:00
|
|
|
}
|
2000-11-26 18:36:16 +00: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-10 23:12:57 +00:00
|
|
|
|
2013-12-30 13:37:32 +00:00
|
|
|
ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), base);
|
|
|
|
if (-1 == ret) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
|
|
|
"Unable to convert variable to GMP - string is not an integer");
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
|
|
|
default:
|
2013-12-30 13:37:32 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING,
|
|
|
|
"Unable to convert variable to GMP - wrong type");
|
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-10 23:12:57 +00:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
static void gmp_strval(zval *result, mpz_t gmpnum, long base) /* {{{ */
|
|
|
|
{
|
|
|
|
int num_len;
|
2014-05-06 16:44:28 +00:00
|
|
|
zend_string *str;
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
num_len = mpz_sizeinbase(gmpnum, abs(base));
|
|
|
|
if (mpz_sgn(gmpnum) < 0) {
|
|
|
|
num_len++;
|
|
|
|
}
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
str = STR_ALLOC(num_len, 0);
|
|
|
|
mpz_get_str(str->val, base, gmpnum);
|
2013-06-17 15:49:24 +00: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...
|
|
|
|
*/
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
if (str->val[str->len - 1] == '\0') {
|
|
|
|
str->len--;
|
2013-06-17 15:49:24 +00:00
|
|
|
} else {
|
2014-05-06 16:44:28 +00:00
|
|
|
str->val[str->len] = '\0';
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
ZVAL_STR(result, str);
|
2013-06-17 15:49:24 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC) /* {{{ */
|
|
|
|
{
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
|
|
|
zend_bool use_si = 0;
|
|
|
|
long res;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (Z_TYPE_P(b_arg) == IS_LONG) {
|
|
|
|
use_si = 1;
|
|
|
|
temp_b.is_used = 0;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_si) {
|
|
|
|
res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg));
|
|
|
|
} else {
|
|
|
|
res = mpz_cmp(gmpnum_a, gmpnum_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
|
|
|
|
|
|
|
RETURN_LONG(res);
|
|
|
|
}
|
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ gmp_zval_binary_ui_op
|
2000-11-26 18:36:16 +00:00
|
|
|
Execute GMP binary operation.
|
|
|
|
*/
|
2013-06-17 15:49:24 +00:00
|
|
|
static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC)
|
2001-08-07 17:57:55 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
|
2003-11-19 05:00:56 +00:00
|
|
|
int use_ui = 0;
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_temp_t temp_a, temp_b;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2003-11-19 05:00:56 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
|
2003-11-19 05:00:56 +00:00
|
|
|
use_ui = 1;
|
2013-06-17 15:49:24 +00:00
|
|
|
temp_b.is_used = 0;
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (check_b_zero) {
|
2005-04-25 12:18:50 +00:00
|
|
|
int b_is_zero = 0;
|
2013-06-17 15:49:24 +00:00
|
|
|
if (use_ui) {
|
|
|
|
b_is_zero = (Z_LVAL_P(b_arg) == 0);
|
2005-04-25 12:18:50 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
|
2005-04-25 12:18:50 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (b_is_zero) {
|
2005-04-25 12:18:50 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
|
2013-06-17 15:49:24 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2005-04-25 12:18:50 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2004-02-15 17:22:57 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2003-11-19 05:00:56 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (use_ui) {
|
|
|
|
gmp_ui_op(gmpnum_result, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg));
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_op(gmpnum_result, gmpnum_a, gmpnum_b);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ gmp_zval_binary_ui_op2
|
2000-11-26 18:36:16 +00:00
|
|
|
Execute GMP binary operation which returns 2 values.
|
|
|
|
*/
|
2013-06-17 15:49:24 +00:00
|
|
|
static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC)
|
2001-08-07 17:57:55 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2;
|
2003-11-19 05:00:56 +00:00
|
|
|
int use_ui = 0;
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_temp_t temp_a, temp_b;
|
2014-05-06 16:44:28 +00:00
|
|
|
zval result1, result2;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2003-11-19 05:00:56 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
|
2000-11-26 18:36:16 +00:00
|
|
|
/* use _ui function */
|
2003-11-19 05:00:56 +00:00
|
|
|
use_ui = 1;
|
2013-06-17 15:49:24 +00:00
|
|
|
temp_b.is_used = 0;
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (check_b_zero) {
|
2005-04-25 12:18:50 +00:00
|
|
|
int b_is_zero = 0;
|
2013-06-17 15:49:24 +00:00
|
|
|
if (use_ui) {
|
|
|
|
b_is_zero = (Z_LVAL_P(b_arg) == 0);
|
2005-04-25 12:18:50 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
|
2005-04-25 12:18:50 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (b_is_zero) {
|
2005-04-25 12:18:50 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed");
|
2013-06-17 15:49:24 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2005-04-25 12:18:50 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2004-02-15 17:22:57 +00:00
|
|
|
}
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_create(&result1, &gmpnum_result1 TSRMLS_CC);
|
|
|
|
gmp_create(&result2, &gmpnum_result2 TSRMLS_CC);
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
array_init(return_value);
|
2014-05-06 16:44:28 +00:00
|
|
|
add_next_index_zval(return_value, &result1);
|
|
|
|
add_next_index_zval(return_value, &result2);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (use_ui) {
|
|
|
|
gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg));
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ _gmp_binary_ui_op
|
|
|
|
*/
|
2013-06-17 15:49:24 +00: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, int check_b_zero)
|
2003-11-19 05:00:56 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
|
|
|
/* Unary operations */
|
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_zval_unary_op
|
|
|
|
*/
|
2013-06-17 15:49:24 +00:00
|
|
|
static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC)
|
2001-08-07 17:57:55 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a;
|
2001-08-07 17:57:55 +00:00
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
gmp_op(gmpnum_result, gmpnum_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ gmp_zval_unary_ui_op
|
|
|
|
*/
|
2013-06-17 15:49:24 +00:00
|
|
|
static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC)
|
2003-11-19 05:00:56 +00:00
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_result;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_op(gmpnum_result, zval_get_long(a_arg));
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ _gmp_unary_ui_op
|
2000-11-26 18:36:16 +00:00
|
|
|
Execute GMP unary operation.
|
|
|
|
*/
|
2003-11-19 05:00:56 +00:00
|
|
|
static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2007-11-01 00:46:13 +00:00
|
|
|
|
2010-09-17 07:07:52 +00:00
|
|
|
gmp_zval_unary_ui_op(return_value, a_arg, gmp_op TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ _gmp_unary_op
|
|
|
|
*/
|
2003-11-19 05:00:56 +00:00
|
|
|
static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2001-08-11 16:39:07 +00:00
|
|
|
gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ _gmp_unary_opl
|
|
|
|
*/
|
2003-11-19 05:00:56 +00:00
|
|
|
static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 15:49:24 +00:00
|
|
|
RETVAL_LONG(gmp_op(gmpnum_a));
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2001-06-05 13:12:10 +00:00
|
|
|
/* {{{ _gmp_binary_opl
|
|
|
|
*/
|
2003-11-19 05:00:56 +00:00
|
|
|
static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2007-11-01 00:46:13 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
RETVAL_LONG(gmp_op(gmpnum_a, gmpnum_b));
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_init(mixed number [, int base])
|
2000-12-01 15:25:22 +00:00
|
|
|
Initializes GMP number */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_init)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *number_arg;
|
|
|
|
mpz_ptr gmpnumber;
|
|
|
|
long base = 0;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &number_arg, &base) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2010-09-15 10:51:55 +00:00
|
|
|
if (base && (base < 2 || base > MAX_BASE)) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
|
2007-11-01 00:46:13 +00:00
|
|
|
RETURN_FALSE;
|
2001-08-05 14:48:17 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnumber);
|
|
|
|
if (convert_to_gmp(gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) {
|
|
|
|
zval_dtor(return_value);
|
2000-11-26 18:36:16 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_intval(mixed gmpnumber)
|
2000-12-01 15:25:22 +00:00
|
|
|
Gets signed long value of GMP number */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_intval)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *gmpnumber_arg;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &gmpnumber_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (IS_GMP(gmpnumber_arg)) {
|
|
|
|
RETVAL_LONG(mpz_get_si(GET_GMP_FROM_ZVAL(gmpnumber_arg)));
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2014-05-06 16:44:28 +00:00
|
|
|
RETVAL_LONG(zval_get_long(gmpnumber_arg));
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto string gmp_strval(mixed gmpnumber [, int base])
|
2000-12-01 15:25:22 +00:00
|
|
|
Gets string representation of GMP number */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_strval)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *gmpnumber_arg;
|
2007-11-01 09:25:11 +00:00
|
|
|
long base = 10;
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &base) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2010-09-15 10:51:55 +00:00
|
|
|
#if MAX_BASE == 62
|
|
|
|
/* Although the maximum base in general in GMP >= 4.2 is 62, mpz_get_str()
|
|
|
|
* is explicitly limited to -36 when dealing with negative bases. */
|
|
|
|
if ((base < 2 && base > -2) || base > MAX_BASE || base < -36) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d or -2 and -36)", base, MAX_BASE);
|
2009-11-27 22:24:44 +00:00
|
|
|
#else
|
2010-09-15 10:51:55 +00:00
|
|
|
if (base < 2 || base > MAX_BASE) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE);
|
2009-11-27 22:24:44 +00:00
|
|
|
#endif
|
2000-12-05 14:17:38 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_strval(return_value, gmpnum, base);
|
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-10 23:12:57 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_add(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Add a and b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_add)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_ui_op(mpz_add, mpz_add_ui);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_sub(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Subtract b from a */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_sub)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_ui_op(mpz_sub, mpz_sub_ui);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_mul(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Multiply a and b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_mul)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_ui_op(mpz_mul, mpz_mul_ui);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto array gmp_div_qr(mixed a, mixed b [, int round])
|
2000-12-01 15:25:22 +00:00
|
|
|
Divide a by b, returns quotient and reminder */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_div_qr)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
2007-11-01 09:25:11 +00:00
|
|
|
long round = GMP_ROUND_ZERO;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 05:00:56 +00:00
|
|
|
switch (round) {
|
2000-11-26 18:36:16 +00:00
|
|
|
case GMP_ROUND_ZERO:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t) mpz_tdiv_qr_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t) mpz_cdiv_qr_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t) mpz_fdiv_qr_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
2013-06-17 15:49:24 +00:00
|
|
|
default:
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode");
|
|
|
|
RETURN_FALSE;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_div_r(mixed a, mixed b [, int round])
|
2000-12-01 15:25:22 +00:00
|
|
|
Divide a by b, returns reminder only */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_div_r)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
2007-11-01 09:25:11 +00:00
|
|
|
long round = GMP_ROUND_ZERO;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 05:00:56 +00:00
|
|
|
switch (round) {
|
2000-11-26 18:36:16 +00:00
|
|
|
case GMP_ROUND_ZERO:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t) mpz_tdiv_r_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t) mpz_cdiv_r_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t) mpz_fdiv_r_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
2013-06-17 15:49:24 +00:00
|
|
|
default:
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode");
|
|
|
|
RETURN_FALSE;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_div_q(mixed a, mixed b [, int round])
|
2000-12-01 15:25:22 +00:00
|
|
|
Divide a by b, returns quotient only */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_div_q)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
2007-11-01 09:25:11 +00:00
|
|
|
long round = GMP_ROUND_ZERO;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2003-11-19 05:00:56 +00:00
|
|
|
switch (round) {
|
2000-11-26 18:36:16 +00:00
|
|
|
case GMP_ROUND_ZERO:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t) mpz_tdiv_q_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t) mpz_cdiv_q_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t) mpz_fdiv_q_ui, 1 TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
break;
|
2013-06-17 15:49:24 +00:00
|
|
|
default:
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode");
|
|
|
|
RETURN_FALSE;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_mod(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Computes a modulo b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_mod)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t) mpz_mod_ui);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_divexact(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Divide a by b using exact division algorithm */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_divexact)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_ui_op_no_zero(mpz_divexact, NULL);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_neg(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Negates a number */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_neg)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_neg);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_abs(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates absolute value */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_abs)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_abs);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_fact(int a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates factorial function */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_fact)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
2005-03-01 13:09:33 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2005-03-01 13:09:33 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (IS_GMP(a_arg)) {
|
|
|
|
mpz_ptr gmpnum_tmp = GET_GMP_FROM_ZVAL(a_arg);
|
|
|
|
if (mpz_sgn(gmpnum_tmp) < 0) {
|
2007-11-01 00:46:13 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
|
2005-03-01 13:09:33 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
2014-05-06 16:44:28 +00:00
|
|
|
if (zval_get_long(a_arg) < 0) {
|
2007-11-01 00:46:13 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
|
2005-03-01 13:09:33 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2013-06-17 15:49:24 +00:00
|
|
|
|
2010-09-17 07:07:52 +00:00
|
|
|
gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_pow(mixed base, int exp)
|
2000-12-01 15:25:22 +00:00
|
|
|
Raise base to power exp */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_pow)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *base_arg;
|
|
|
|
mpz_ptr gmpnum_result, gmpnum_base;
|
|
|
|
gmp_temp_t temp_base;
|
2007-11-01 09:25:11 +00:00
|
|
|
long exp;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &base_arg, &exp) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 09:25:11 +00:00
|
|
|
if (exp < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported");
|
2000-11-26 18:36:16 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) {
|
|
|
|
mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp);
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
|
|
|
|
mpz_pow_ui(gmpnum_result, gmpnum_base, exp);
|
2007-11-01 09:34:18 +00:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_powm(mixed base, mixed exp, mixed mod)
|
2000-12-01 15:25:22 +00:00
|
|
|
Raise base to power exp and take result modulo mod */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_powm)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *base_arg, *exp_arg, *mod_arg;
|
|
|
|
mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
|
2003-11-19 05:00:56 +00:00
|
|
|
int use_ui = 0;
|
2013-10-29 19:07:34 +00:00
|
|
|
gmp_temp_t temp_base, temp_exp, temp_mod;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
|
2003-11-19 05:00:56 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) {
|
2003-11-19 05:00:56 +00:00
|
|
|
use_ui = 1;
|
2013-06-17 15:49:24 +00:00
|
|
|
temp_exp.is_used = 0;
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base);
|
|
|
|
if (mpz_sgn(gmpnum_exp) < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second parameter cannot be less than 0");
|
|
|
|
FREE_GMP_TEMP(temp_base);
|
|
|
|
FREE_GMP_TEMP(temp_exp);
|
2005-03-01 13:09:33 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (!mpz_cmp_ui(gmpnum_mod, 0)) {
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
2007-11-01 09:34:18 +00:00
|
|
|
if (use_ui) {
|
|
|
|
FREE_GMP_TEMP(temp_exp);
|
|
|
|
}
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_mod);
|
2004-02-15 17:22:57 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2003-11-19 05:00:56 +00:00
|
|
|
if (use_ui) {
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_powm_ui(gmpnum_result, gmpnum_base, (unsigned long) Z_LVAL_P(exp_arg), gmpnum_mod);
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
|
2007-11-01 09:34:18 +00:00
|
|
|
FREE_GMP_TEMP(temp_exp);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
|
|
|
FREE_GMP_TEMP(temp_mod);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_sqrt(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Takes integer part of square root of a */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_sqrt)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a;
|
2005-03-01 13:09:33 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2005-03-01 13:09:33 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2005-03-01 13:09:33 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (mpz_sgn(gmpnum_a) < 0) {
|
2007-11-01 00:46:13 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2005-03-01 13:09:33 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
mpz_sqrt(gmpnum_result, gmpnum_a);
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto array gmp_sqrtrem(mixed a)
|
2001-12-15 14:23:07 +00:00
|
|
|
Square root with remainder */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_sqrtrem)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
|
|
|
|
gmp_temp_t temp_a;
|
2014-05-06 16:44:28 +00:00
|
|
|
zval result1, result2;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 15:49:24 +00:00
|
|
|
|
|
|
|
if (mpz_sgn(gmpnum_a) < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0");
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2005-03-01 13:09:33 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_create(&result1, &gmpnum_result1 TSRMLS_CC);
|
|
|
|
gmp_create(&result2, &gmpnum_result2 TSRMLS_CC);
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
array_init(return_value);
|
2014-05-06 16:44:28 +00:00
|
|
|
add_next_index_zval(return_value, &result1);
|
|
|
|
add_next_index_zval(return_value, &result2);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a);
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-28 22:42:23 +00:00
|
|
|
/* {{{ proto GMP gmp_root(mixed a, int nth)
|
|
|
|
Takes integer part of nth root */
|
|
|
|
ZEND_FUNCTION(gmp_root)
|
|
|
|
{
|
|
|
|
zval *a_arg;
|
|
|
|
long nth;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a;
|
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &nth) == FAILURE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nth <= 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The root must be positive");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
|
|
|
|
if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't take even root of negative number");
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
mpz_root(gmpnum_result, gmpnum_a, (unsigned long) nth);
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto GMP gmp_rootrem(mixed a, int nth)
|
|
|
|
Calculates integer part of nth root and remainder */
|
|
|
|
ZEND_FUNCTION(gmp_rootrem)
|
|
|
|
{
|
|
|
|
zval *a_arg;
|
|
|
|
long nth;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
|
|
|
|
gmp_temp_t temp_a;
|
2014-05-06 16:44:28 +00:00
|
|
|
zval result1, result2;
|
2013-11-28 22:42:23 +00:00
|
|
|
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &nth) == FAILURE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nth <= 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The root must be positive");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
|
|
|
|
if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't take even root of negative number");
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_create(&result1, &gmpnum_result1 TSRMLS_CC);
|
|
|
|
gmp_create(&result2, &gmpnum_result2 TSRMLS_CC);
|
|
|
|
|
2013-11-28 22:42:23 +00:00
|
|
|
array_init(return_value);
|
2014-05-06 16:44:28 +00:00
|
|
|
add_next_index_zval(return_value, &result1);
|
|
|
|
add_next_index_zval(return_value, &result2);
|
2013-11-28 22:42:23 +00:00
|
|
|
|
2013-12-02 19:10:08 +00:00
|
|
|
#if GMP_42_OR_NEWER
|
2013-11-28 22:42:23 +00:00
|
|
|
mpz_rootrem(gmpnum_result1, gmpnum_result2, gmpnum_a, (unsigned long) nth);
|
2013-12-02 19:10:08 +00:00
|
|
|
#else
|
|
|
|
mpz_root(gmpnum_result1, gmpnum_a, (unsigned long) nth);
|
|
|
|
mpz_pow_ui(gmpnum_result2, gmpnum_result1, (unsigned long) nth);
|
|
|
|
mpz_sub(gmpnum_result2, gmpnum_a, gmpnum_result2);
|
|
|
|
mpz_abs(gmpnum_result2, gmpnum_result2);
|
|
|
|
#endif
|
|
|
|
|
2013-11-28 22:42:23 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto bool gmp_perfect_square(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Checks if a is an exact square */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_perfect_square)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0));
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_prob_prime(mixed a[, int reps])
|
2000-12-06 14:10:40 +00:00
|
|
|
Checks if a is "probably prime" */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_prob_prime)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *gmpnumber_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
2007-11-01 09:25:11 +00:00
|
|
|
long reps = 10;
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_temp_t temp_a;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &reps) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, reps));
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_gcd(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Computes greatest common denominator (gcd) of a and b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_gcd)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t) mpz_gcd_ui);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto array gmp_gcdext(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_gcdext)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
2014-05-06 16:44:28 +00:00
|
|
|
zval result_g, result_s, result_t;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2014-05-06 16:44:28 +00:00
|
|
|
gmp_create(&result_g, &gmpnum_g TSRMLS_CC);
|
|
|
|
gmp_create(&result_s, &gmpnum_s TSRMLS_CC);
|
|
|
|
gmp_create(&result_t, &gmpnum_t TSRMLS_CC);
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
array_init(return_value);
|
2014-05-06 16:44:28 +00:00
|
|
|
add_assoc_zval(return_value, "g", &result_g);
|
|
|
|
add_assoc_zval(return_value, "s", &result_s);
|
|
|
|
add_assoc_zval(return_value, "t", &result_t);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b);
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_invert(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Computes the inverse of a modulo b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_invert)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
2007-11-01 00:46:13 +00:00
|
|
|
int res;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b);
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2013-06-17 15:49:24 +00:00
|
|
|
if (!res) {
|
|
|
|
zval_dtor(return_value);
|
2000-11-26 18:36:16 +00:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_jacobi(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Computes Jacobi symbol */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_jacobi)
|
|
|
|
{
|
2000-11-29 15:49:18 +00:00
|
|
|
gmp_binary_opl(mpz_jacobi);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_legendre(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Computes Legendre symbol */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_legendre)
|
|
|
|
{
|
2000-11-29 15:49:18 +00:00
|
|
|
gmp_binary_opl(mpz_legendre);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_cmp(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Compares two numbers */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_cmp)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg, *b_arg;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_cmp(return_value, a_arg, b_arg TSRMLS_CC);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_sign(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Gets the sign of the number */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_sign)
|
|
|
|
{
|
2013-11-23 11:54:20 +00:00
|
|
|
/* Can't use gmp_unary_opl here, because mpz_sgn is a macro */
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2013-11-23 11:54:20 +00:00
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
RETVAL_LONG(mpz_sgn(gmpnum_a));
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_random([int limiter])
|
2000-12-01 15:25:22 +00:00
|
|
|
Gets random number */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_random)
|
|
|
|
{
|
2007-11-01 09:25:11 +00:00
|
|
|
long limiter = 20;
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_result;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) {
|
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2003-11-19 04:44:06 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2010-02-23 11:07:39 +00:00
|
|
|
#ifdef GMP_LIMB_BITS
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
|
2010-02-23 11:07:39 +00:00
|
|
|
#else
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
|
2010-02-23 11:07:39 +00:00
|
|
|
#endif
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_and(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates logical AND of a and b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_and)
|
|
|
|
{
|
|
|
|
gmp_binary_op(mpz_and);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_or(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates logical OR of a and b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_or)
|
|
|
|
{
|
|
|
|
gmp_binary_op(mpz_ior);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_com(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates one's complement of a */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_com)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_com);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_nextprime(mixed a)
|
2006-07-18 14:54:32 +00:00
|
|
|
Finds next prime of a */
|
|
|
|
ZEND_FUNCTION(gmp_nextprime)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_nextprime);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto GMP gmp_xor(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates logical exclusive OR of a and b */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_xor)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
gmp_binary_op(mpz_xor);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
/* {{{ proto void gmp_setbit(GMP a, int index[, bool set_clear])
|
2000-12-01 15:25:22 +00:00
|
|
|
Sets or clear bit in a */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_setbit)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
2007-11-01 09:25:11 +00:00
|
|
|
long index;
|
|
|
|
zend_bool set = 1;
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_a;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) {
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-04-18 20:36:54 +00:00
|
|
|
if (index < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
|
|
|
|
|
2003-11-19 05:00:56 +00:00
|
|
|
if (set) {
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_setbit(gmpnum_a, index);
|
2000-11-26 18:36:16 +00:00
|
|
|
} else {
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_clrbit(gmpnum_a, index);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-28 23:00:41 +00:00
|
|
|
/* {{{ proto void gmp_clrbit(GMP a, int index)
|
2000-12-01 15:25:22 +00:00
|
|
|
Clears bit in a */
|
2000-11-26 18:36:16 +00:00
|
|
|
ZEND_FUNCTION(gmp_clrbit)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
2007-11-01 09:25:11 +00:00
|
|
|
long index;
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_a;
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &a_arg, gmp_ce, &index) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
|
2007-04-18 20:36:54 +00:00
|
|
|
if (index < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
|
|
|
|
return;
|
|
|
|
}
|
2000-11-26 18:36:16 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
|
|
|
|
mpz_clrbit(gmpnum_a, index);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto bool gmp_testbit(mixed a, int index)
|
2007-11-01 17:51:34 +00:00
|
|
|
Tests if bit is set in a */
|
|
|
|
ZEND_FUNCTION(gmp_testbit)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
2007-11-01 20:25:11 +00:00
|
|
|
long index;
|
2013-06-17 15:49:24 +00:00
|
|
|
mpz_ptr gmpnum_a;
|
2014-03-10 11:06:40 +00:00
|
|
|
gmp_temp_t temp_a;
|
2007-11-01 17:51:34 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &index) == FAILURE){
|
2007-11-01 17:51:34 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 0) {
|
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-03-10 11:06:40 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
RETVAL_BOOL(mpz_tstbit(gmpnum_a, index));
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2007-11-01 17:51:34 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_popcount(mixed a)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates the population count of a */
|
2000-11-29 15:49:18 +00:00
|
|
|
ZEND_FUNCTION(gmp_popcount)
|
|
|
|
{
|
2013-11-23 11:54:20 +00:00
|
|
|
gmp_unary_opl((gmp_unary_opl_t) mpz_popcount);
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_hamdist(mixed a, mixed b)
|
2000-12-01 15:25:22 +00:00
|
|
|
Calculates hamming distance between a and b */
|
2000-11-29 15:49:18 +00:00
|
|
|
ZEND_FUNCTION(gmp_hamdist)
|
|
|
|
{
|
2013-11-23 11:54:20 +00:00
|
|
|
gmp_binary_opl((gmp_binary_opl_t) mpz_hamdist);
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_scan0(mixed a, int start)
|
2000-12-01 15:25:22 +00:00
|
|
|
Finds first zero bit */
|
2000-11-29 15:49:18 +00:00
|
|
|
ZEND_FUNCTION(gmp_scan0)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2007-11-01 09:25:11 +00:00
|
|
|
long start;
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
if (start < 0) {
|
2007-04-18 20:53:28 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
|
|
|
|
RETVAL_LONG(mpz_scan0(gmpnum_a, start));
|
2007-11-01 00:46:13 +00:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
/* {{{ proto int gmp_scan1(mixed a, int start)
|
2000-12-01 15:25:22 +00:00
|
|
|
Finds first non-zero bit */
|
2000-11-29 15:49:18 +00:00
|
|
|
ZEND_FUNCTION(gmp_scan1)
|
|
|
|
{
|
2013-06-17 15:49:24 +00:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2007-11-01 09:25:11 +00:00
|
|
|
long start;
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){
|
2007-11-01 00:46:13 +00:00
|
|
|
return;
|
2000-11-29 15:49:18 +00:00
|
|
|
}
|
|
|
|
|
2007-11-01 00:46:13 +00:00
|
|
|
if (start < 0) {
|
2007-04-18 20:53:28 +00:00
|
|
|
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2000-11-29 15:49:18 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2001-07-31 05:44:11 +00:00
|
|
|
|
2013-06-17 15:49:24 +00:00
|
|
|
RETVAL_LONG(mpz_scan1(gmpnum_a, start));
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-26 18:36:16 +00:00
|
|
|
}
|
2001-06-05 13:12:10 +00:00
|
|
|
/* }}} */
|
2000-11-26 18:36:16 +00:00
|
|
|
|
|
|
|
#endif /* HAVE_GMP */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Local variables:
|
|
|
|
* tab-width: 4
|
|
|
|
* c-basic-offset: 4
|
|
|
|
* End:
|
2006-06-14 21:36:10 +00:00
|
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
|
|
* vim<600: noet sw=4 ts=4
|
2000-11-26 18:36:16 +00:00
|
|
|
*/
|