2000-11-27 02:36:16 +08:00
|
|
|
/*
|
|
|
|
+----------------------------------------------------------------------+
|
2014-09-20 00:33:14 +08:00
|
|
|
| PHP Version 7 |
|
2000-11-27 02:36:16 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2015-01-15 23:27:30 +08:00
|
|
|
| Copyright (c) 1997-2015 The PHP Group |
|
2000-11-27 02:36:16 +08:00
|
|
|
+----------------------------------------------------------------------+
|
2006-01-01 20:51:34 +08:00
|
|
|
| This source file is subject to version 3.01 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: |
|
2006-01-01 20:51:34 +08:00
|
|
|
| http://www.php.net/license/3_01.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"
|
2013-10-30 03:58:30 +08:00
|
|
|
#include "ext/standard/php_var.h"
|
2014-09-21 04:42:02 +08:00
|
|
|
#include "zend_smart_str_public.h"
|
2013-06-17 23:49:24 +08:00
|
|
|
#include "zend_exceptions.h"
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
#if HAVE_GMP
|
|
|
|
|
|
|
|
#include <gmp.h>
|
2003-11-19 12:44:06 +08: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-27 02:36:16 +08:00
|
|
|
|
2006-06-15 05:36:10 +08: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()
|
|
|
|
|
2014-08-28 04:45:05 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_import, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, data)
|
|
|
|
ZEND_ARG_INFO(0, word_size)
|
|
|
|
ZEND_ARG_INFO(0, options)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_export, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, gmpnumber)
|
|
|
|
ZEND_ARG_INFO(0, word_size)
|
|
|
|
ZEND_ARG_INFO(0, options)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_intval, 0, 0, 1)
|
2006-06-15 05:36:10 +08: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-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_unary, 0, 0, 1)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_binary, 0, 0, 2)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, b)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div, 0, 0, 2)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, b)
|
|
|
|
ZEND_ARG_INFO(0, round)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_pow, 0, 0, 2)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, base)
|
|
|
|
ZEND_ARG_INFO(0, exp)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_powm, 0, 0, 3)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, base)
|
|
|
|
ZEND_ARG_INFO(0, exp)
|
|
|
|
ZEND_ARG_INFO(0, mod)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_root, 0, 0, 2)
|
2013-11-29 06:42:23 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, nth)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2006-06-15 05:36:10 +08: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()
|
|
|
|
|
2014-10-20 00:25:05 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_seed, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, seed)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2014-09-24 05:12:23 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_bits, 0, 0, 1)
|
|
|
|
ZEND_ARG_INFO(0, bits)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random_range, 0, 0, 2)
|
|
|
|
ZEND_ARG_INFO(0, min)
|
|
|
|
ZEND_ARG_INFO(0, max)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2)
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, index)
|
|
|
|
ZEND_ARG_INFO(0, set_clear)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_bit, 0, 0, 2)
|
2007-11-02 01:51:34 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, index)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_scan, 0, 0, 2)
|
2006-06-15 05:36:10 +08:00
|
|
|
ZEND_ARG_INFO(0, a)
|
|
|
|
ZEND_ARG_INFO(0, start)
|
|
|
|
ZEND_END_ARG_INFO()
|
|
|
|
|
|
|
|
/* }}} */
|
|
|
|
|
2006-06-16 02:33:09 +08:00
|
|
|
ZEND_DECLARE_MODULE_GLOBALS(gmp)
|
|
|
|
static ZEND_GINIT_FUNCTION(gmp);
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ gmp_functions[]
|
|
|
|
*/
|
2007-09-28 02:00:48 +08:00
|
|
|
const zend_function_entry gmp_functions[] = {
|
2013-11-29 07:00:41 +08:00
|
|
|
ZEND_FE(gmp_init, arginfo_gmp_init)
|
2014-08-28 04:45:05 +08:00
|
|
|
ZEND_FE(gmp_import, arginfo_gmp_import)
|
|
|
|
ZEND_FE(gmp_export, arginfo_gmp_export)
|
2013-11-29 07:00:41 +08:00
|
|
|
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)
|
2014-10-20 00:25:05 +08:00
|
|
|
ZEND_FE(gmp_random_seed, arginfo_gmp_random_seed)
|
2014-09-24 05:12:23 +08:00
|
|
|
ZEND_FE(gmp_random_bits, arginfo_gmp_random_bits)
|
|
|
|
ZEND_FE(gmp_random_range, arginfo_gmp_random_range)
|
2013-11-29 07:00:41 +08:00
|
|
|
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 19:35:02 +08:00
|
|
|
PHP_FE_END
|
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_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),
|
2007-01-12 20:32:15 +08: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-11 07:12:57 +08:00
|
|
|
NULL,
|
2003-11-19 12:44:06 +08:00
|
|
|
ZEND_MODULE_DEACTIVATE_N(gmp),
|
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,
|
2006-06-16 02:33:09 +08:00
|
|
|
ZEND_MODULE_GLOBALS(gmp),
|
|
|
|
ZEND_GINIT(gmp),
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
STANDARD_MODULE_PROPERTIES_EX
|
2000-11-27 02:36:16 +08:00
|
|
|
};
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
#ifdef COMPILE_DL_GMP
|
2014-10-17 21:51:21 +08:00
|
|
|
#ifdef ZTS
|
|
|
|
ZEND_TSRMLS_CACHE_DEFINE;
|
|
|
|
#endif
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_GET_MODULE(gmp)
|
|
|
|
#endif
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
zend_class_entry *gmp_ce;
|
|
|
|
static zend_object_handlers gmp_object_handlers;
|
|
|
|
|
|
|
|
typedef struct _gmp_object {
|
|
|
|
mpz_t num;
|
2014-05-07 00:44:28 +08:00
|
|
|
zend_object std;
|
2013-06-17 23:49:24 +08:00
|
|
|
} gmp_object;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
typedef struct _gmp_temp {
|
|
|
|
mpz_t num;
|
|
|
|
zend_bool is_used;
|
|
|
|
} gmp_temp_t;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
#define GMP_ROUND_ZERO 0
|
|
|
|
#define GMP_ROUND_PLUSINF 1
|
|
|
|
#define GMP_ROUND_MINUSINF 2
|
|
|
|
|
2014-08-28 04:45:05 +08:00
|
|
|
#define GMP_MSW_FIRST (1 << 0)
|
|
|
|
#define GMP_LSW_FIRST (1 << 1)
|
|
|
|
#define GMP_LITTLE_ENDIAN (1 << 2)
|
|
|
|
#define GMP_BIG_ENDIAN (1 << 3)
|
|
|
|
#define GMP_NATIVE_ENDIAN (1 << 4)
|
|
|
|
|
2014-09-29 02:39:19 +08:00
|
|
|
#define GMP_MAX_BASE 62
|
2010-09-15 18:51:55 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
#define IS_GMP(zval) \
|
2014-12-14 06:06:14 +08:00
|
|
|
(Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce))
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-05-07 00:44:28 +08: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 23:49:24 +08:00
|
|
|
#define GET_GMP_FROM_ZVAL(zval) \
|
2014-05-07 00:44:28 +08:00
|
|
|
GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
|
2013-06-17 23:49:24 +08: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); \
|
2014-12-14 06:06:14 +08:00
|
|
|
if (convert_to_gmp(temp.num, zval, 0) == FAILURE) { \
|
2013-06-17 23:49:24 +08:00
|
|
|
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); \
|
2014-12-14 06:06:14 +08:00
|
|
|
if (convert_to_gmp(temp.num, zval, 0) == FAILURE) { \
|
2013-06-17 23:49:24 +08:00
|
|
|
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); \
|
2014-12-14 06:06:14 +08:00
|
|
|
if (convert_to_gmp(temp.num, zval, 0) == FAILURE) { \
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_clear(temp.num); \
|
|
|
|
RETURN_FALSE; \
|
|
|
|
} \
|
|
|
|
temp.is_used = 1; \
|
|
|
|
gmpnumber = temp.num; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define INIT_GMP_RETVAL(gmpnumber) \
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_create(return_value, &gmpnumber)
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2015-02-05 01:12:56 +08:00
|
|
|
static void gmp_strval(zval *result, mpz_t gmpnum, int base);
|
2014-12-14 06:06:14 +08:00
|
|
|
static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base);
|
|
|
|
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-08-28 04:45:05 +08:00
|
|
|
/*
|
2013-06-17 23:49:24 +08:00
|
|
|
* 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);
|
|
|
|
|
2014-09-03 00:19:51 +08:00
|
|
|
typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
|
|
|
|
typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr);
|
|
|
|
|
2014-09-03 00:19:51 +08:00
|
|
|
typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong);
|
2013-06-17 23:49:24 +08:00
|
|
|
typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
|
2014-09-03 00:19:51 +08:00
|
|
|
typedef void (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-12-14 06:06:14 +08: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);
|
|
|
|
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);
|
|
|
|
static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op);
|
|
|
|
static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void gmp_free_object_storage(zend_object *obj) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2014-05-07 00:44:28 +08:00
|
|
|
gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
mpz_clear(intern->num);
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_object_std_dtor(&intern->std);
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static inline zend_object *gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2015-02-04 20:24:13 +08:00
|
|
|
gmp_object *intern = emalloc(sizeof(gmp_object) + zend_object_properties_size(ce));
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_object_std_init(&intern->std, ce);
|
2013-06-17 23:49:24 +08:00
|
|
|
object_properties_init(&intern->std, ce);
|
|
|
|
|
|
|
|
mpz_init(intern->num);
|
|
|
|
*gmpnum_target = intern->num;
|
2014-05-07 00:44:28 +08:00
|
|
|
intern->std.handlers = &gmp_object_handlers;
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
return &intern->std;
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static zend_object *gmp_create_object(zend_class_entry *ce) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
|
|
|
mpz_ptr gmpnum_dummy;
|
2014-12-14 06:06:14 +08:00
|
|
|
return gmp_create_object_ex(ce, &gmpnum_dummy);
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static inline void gmp_create(zval *target, mpz_ptr *gmpnum_target) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2014-12-14 06:06:14 +08:00
|
|
|
ZVAL_OBJ(target, gmp_create_object_ex(gmp_ce, gmpnum_target));
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static int gmp_cast_object(zval *readobj, zval *writeobj, int type) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
|
|
|
mpz_ptr gmpnum;
|
|
|
|
switch (type) {
|
|
|
|
case IS_STRING:
|
|
|
|
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
|
|
|
gmp_strval(writeobj, gmpnum, 10);
|
|
|
|
return SUCCESS;
|
2014-08-26 01:24:55 +08:00
|
|
|
case IS_LONG:
|
2013-06-17 23:49:24 +08:00
|
|
|
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
2014-08-26 01:24:55 +08:00
|
|
|
ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
|
2013-06-17 23:49:24 +08:00
|
|
|
return SUCCESS;
|
|
|
|
case IS_DOUBLE:
|
|
|
|
gmpnum = GET_GMP_FROM_ZVAL(readobj);
|
|
|
|
ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
|
|
|
|
return SUCCESS;
|
|
|
|
default:
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static HashTable *gmp_get_debug_info(zval *obj, int *is_temp) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2014-12-14 06:06:14 +08:00
|
|
|
HashTable *ht, *props = zend_std_get_properties(obj);
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(obj);
|
2014-05-07 00:44:28 +08:00
|
|
|
zval zv;
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2013-10-30 03:58:30 +08:00
|
|
|
*is_temp = 1;
|
2015-02-14 03:20:39 +08:00
|
|
|
ht = zend_array_dup(props);
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
gmp_strval(&zv, gmpnum, 10);
|
|
|
|
zend_hash_str_update(ht, "num", sizeof("num")-1, &zv);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
return ht;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static zend_object *gmp_clone_obj(zval *obj) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2014-05-07 00:44:28 +08:00
|
|
|
gmp_object *old_object = GET_GMP_OBJECT_FROM_ZVAL(obj);
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_object *new_object = GET_GMP_OBJECT_FROM_OBJ(gmp_create_object(Z_OBJCE_P(obj)));
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_objects_clone_members( &new_object->std, &old_object->std);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
mpz_set(new_object->num, old_object->num);
|
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
return &new_object->std;
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2) {
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long shift = zval_get_long(op2);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
if (shift < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Shift cannot be negative");
|
2013-06-17 23:49:24 +08:00
|
|
|
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-09-03 00:19:51 +08:00
|
|
|
op(gmpnum_result, gmpnum_op, (gmp_ulong) shift);
|
2013-06-17 23:49:24 +08: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, \
|
2014-12-14 21:07:59 +08:00
|
|
|
check_b_zero \
|
2013-06-17 23:49:24 +08:00
|
|
|
); \
|
|
|
|
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) \
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_zval_unary_op(result, op1, op); \
|
2013-06-17 23:49:24 +08:00
|
|
|
return SUCCESS;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static int gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
|
|
|
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 15:36:06 +08:00
|
|
|
case ZEND_POW:
|
2014-12-14 06:06:14 +08:00
|
|
|
shift_operator_helper(mpz_pow_ui, result, op1, op2);
|
2013-11-19 15:36:06 +08:00
|
|
|
return SUCCESS;
|
2013-06-17 23:49:24 +08: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:
|
2014-12-14 06:06:14 +08:00
|
|
|
shift_operator_helper(mpz_mul_2exp, result, op1, op2);
|
2013-06-17 23:49:24 +08:00
|
|
|
return SUCCESS;
|
|
|
|
case ZEND_SR:
|
2014-12-14 06:06:14 +08:00
|
|
|
shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2);
|
2013-06-17 23:49:24 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */
|
2014-08-28 04:15:20 +08:00
|
|
|
{
|
|
|
|
zval op1_copy;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
if (result == op1) {
|
|
|
|
ZVAL_COPY_VALUE(&op1_copy, op1);
|
|
|
|
op1 = &op1_copy;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
retval = gmp_do_operation_ex(opcode, result, op1, op2);
|
2014-08-28 04:15:20 +08:00
|
|
|
|
|
|
|
if (retval == SUCCESS && op1 == &op1_copy) {
|
|
|
|
zval_dtor(op1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static int gmp_compare(zval *result, zval *op1, zval *op2) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_cmp(result, op1, op2);
|
2014-05-07 00:44:28 +08:00
|
|
|
if (Z_TYPE_P(result) == IS_FALSE) {
|
2014-08-26 01:24:55 +08:00
|
|
|
ZVAL_LONG(result, 1);
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static int gmp_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2013-11-24 07:43:12 +08:00
|
|
|
mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(object);
|
2013-10-30 03:58:30 +08:00
|
|
|
smart_str buf = {0};
|
2014-05-07 00:44:28 +08:00
|
|
|
zval zv;
|
2014-04-28 16:01:54 +08:00
|
|
|
php_serialize_data_t serialize_data = (php_serialize_data_t) data;
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2014-04-28 16:01:54 +08:00
|
|
|
PHP_VAR_SERIALIZE_INIT(serialize_data);
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
gmp_strval(&zv, gmpnum, 10);
|
2014-12-14 06:06:14 +08:00
|
|
|
php_var_serialize(&buf, &zv, &serialize_data);
|
2014-05-07 00:44:28 +08:00
|
|
|
zval_dtor(&zv);
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2015-02-14 03:20:39 +08:00
|
|
|
ZVAL_ARR(&zv, zend_std_get_properties(object));
|
2014-12-14 06:06:14 +08:00
|
|
|
php_var_serialize(&buf, &zv, &serialize_data);
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2014-04-28 16:01:54 +08:00
|
|
|
PHP_VAR_SERIALIZE_DESTROY(serialize_data);
|
2014-05-07 00:44:28 +08:00
|
|
|
*buffer = (unsigned char *) estrndup(buf.s->val, buf.s->len);
|
|
|
|
*buf_len = buf.s->len;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_string_release(buf.s);
|
2013-11-24 07:43:12 +08:00
|
|
|
|
|
|
|
return SUCCESS;
|
2013-10-30 03:58:30 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) /* {{{ */
|
2013-10-30 03:58:30 +08:00
|
|
|
{
|
2013-11-24 07:43:12 +08:00
|
|
|
mpz_ptr gmpnum;
|
2013-10-30 03:58:30 +08:00
|
|
|
const unsigned char *p, *max;
|
2014-05-07 00:44:28 +08:00
|
|
|
zval zv;
|
2013-11-24 07:43:12 +08:00
|
|
|
int retval = FAILURE;
|
2014-04-28 16:01:54 +08:00
|
|
|
php_unserialize_data_t unserialize_data = (php_unserialize_data_t) data;
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2014-05-13 16:57:42 +08:00
|
|
|
ZVAL_UNDEF(&zv);
|
2014-04-28 16:01:54 +08:00
|
|
|
PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_create(object, &gmpnum);
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2013-11-24 07:43:12 +08:00
|
|
|
p = buf;
|
|
|
|
max = buf + buf_len;
|
2013-10-30 03:58:30 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (!php_var_unserialize(&zv, &p, max, &unserialize_data)
|
2014-05-07 00:44:28 +08:00
|
|
|
|| Z_TYPE(zv) != IS_STRING
|
2014-12-14 06:06:14 +08:00
|
|
|
|| convert_to_gmp(gmpnum, &zv, 10) == FAILURE
|
2013-06-17 23:49:24 +08:00
|
|
|
) {
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_throw_exception(NULL, "Could not unserialize number", 0);
|
2013-10-30 03:58:30 +08:00
|
|
|
goto exit;
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
2013-10-30 03:58:30 +08:00
|
|
|
zval_dtor(&zv);
|
2014-05-13 16:57:42 +08:00
|
|
|
ZVAL_UNDEF(&zv);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (!php_var_unserialize(&zv, &p, max, &unserialize_data)
|
2014-05-07 00:44:28 +08:00
|
|
|
|| Z_TYPE(zv) != IS_ARRAY
|
2013-10-30 03:58:30 +08:00
|
|
|
) {
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_throw_exception(NULL, "Could not unserialize properties", 0);
|
2013-10-30 03:58:30 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
if (zend_hash_num_elements(Z_ARRVAL(zv)) != 0) {
|
2013-10-30 03:58:30 +08:00
|
|
|
zend_hash_copy(
|
2014-12-14 06:06:14 +08:00
|
|
|
zend_std_get_properties(object), Z_ARRVAL(zv),
|
2014-05-07 00:44:28 +08:00
|
|
|
(copy_ctor_func_t) zval_add_ref
|
2013-10-30 03:58:30 +08:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-11-24 07:43:12 +08:00
|
|
|
retval = SUCCESS;
|
2013-10-30 03:58:30 +08:00
|
|
|
exit:
|
|
|
|
zval_dtor(&zv);
|
2014-04-28 16:01:54 +08:00
|
|
|
PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
|
2013-11-24 07:43:12 +08:00
|
|
|
return retval;
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2006-06-16 02:33:09 +08:00
|
|
|
/* {{{ ZEND_GINIT_FUNCTION
|
2003-11-19 12:44:06 +08:00
|
|
|
*/
|
2006-06-16 02:33:09 +08:00
|
|
|
static ZEND_GINIT_FUNCTION(gmp)
|
2003-11-19 12:44:06 +08:00
|
|
|
{
|
2014-10-17 21:51:21 +08:00
|
|
|
#if defined(COMPILE_DL_GMP) && defined(ZTS)
|
|
|
|
ZEND_TSRMLS_CACHE_UPDATE;
|
|
|
|
#endif
|
2003-11-19 12:44:06 +08:00
|
|
|
gmp_globals->rand_initialized = 0;
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2001-06-07 01:52:03 +08:00
|
|
|
/* {{{ ZEND_MINIT_FUNCTION
|
2001-06-05 21:12:10 +08:00
|
|
|
*/
|
2013-06-17 23:49:24 +08:00
|
|
|
ZEND_MINIT_FUNCTION(gmp)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zend_class_entry tmp_ce;
|
2013-11-24 07:43:12 +08:00
|
|
|
INIT_CLASS_ENTRY(tmp_ce, "GMP", NULL);
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_ce = zend_register_internal_class(&tmp_ce);
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_ce->create_object = gmp_create_object;
|
2013-11-24 07:43:12 +08:00
|
|
|
gmp_ce->serialize = gmp_serialize;
|
|
|
|
gmp_ce->unserialize = gmp_unserialize;
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
memcpy(&gmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
|
2014-05-07 00:44:28 +08:00
|
|
|
gmp_object_handlers.offset = XtOffsetOf(gmp_object, std);
|
|
|
|
gmp_object_handlers.free_obj = gmp_free_object_storage;
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_object_handlers.cast_object = gmp_cast_object;
|
2013-10-30 03:58:30 +08:00
|
|
|
gmp_object_handlers.get_debug_info = gmp_get_debug_info;
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_object_handlers.clone_obj = gmp_clone_obj;
|
|
|
|
gmp_object_handlers.do_operation = gmp_do_operation;
|
|
|
|
gmp_object_handlers.compare = gmp_compare;
|
|
|
|
|
2014-08-26 01:24:55 +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);
|
2009-12-10 10:25:47 +08:00
|
|
|
#ifdef mpir_version
|
|
|
|
REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
|
|
|
|
#endif
|
2007-04-26 21:44:02 +08:00
|
|
|
REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
|
2000-12-05 23:35:20 +08:00
|
|
|
|
2014-08-28 04:45:05 +08:00
|
|
|
REGISTER_LONG_CONSTANT("GMP_MSW_FIRST", GMP_MSW_FIRST, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("GMP_LSW_FIRST", GMP_LSW_FIRST, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("GMP_LITTLE_ENDIAN", GMP_LITTLE_ENDIAN, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("GMP_BIG_ENDIAN", GMP_BIG_ENDIAN, CONST_CS | CONST_PERSISTENT);
|
|
|
|
REGISTER_LONG_CONSTANT("GMP_NATIVE_ENDIAN", GMP_NATIVE_ENDIAN, CONST_CS | CONST_PERSISTENT);
|
|
|
|
|
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
|
|
|
|
2003-11-19 12:44:06 +08: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-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");
|
2009-12-10 10:25:47 +08:00
|
|
|
#ifdef mpir_version
|
|
|
|
php_info_print_table_row(2, "MPIR version", mpir_version);
|
|
|
|
#else
|
2007-04-26 21:44:02 +08:00
|
|
|
php_info_print_table_row(2, "GMP version", gmp_version);
|
2009-12-10 10:25:47 +08:00
|
|
|
#endif
|
2000-11-27 02:36:16 +08:00
|
|
|
php_info_print_table_end();
|
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
|
|
|
|
2001-06-05 21:12:10 +08:00
|
|
|
/* {{{ convert_to_gmp
|
|
|
|
* Convert zval to be gmp number */
|
2014-12-14 06:06:14 +08:00
|
|
|
static int convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base)
|
2000-11-27 02:36:16 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
switch (Z_TYPE_P(val)) {
|
2014-08-26 01:24:55 +08:00
|
|
|
case IS_LONG:
|
2014-05-07 00:44:28 +08:00
|
|
|
case IS_FALSE:
|
|
|
|
case IS_TRUE: {
|
2014-08-26 01:24:55 +08:00
|
|
|
mpz_set_si(gmpnumber, zval_get_long(val));
|
2013-06-17 23:49:24 +08:00
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
case IS_STRING: {
|
|
|
|
char *numstr = Z_STRVAL_P(val);
|
2014-09-03 00:42:39 +08:00
|
|
|
zend_bool skip_lead = 0;
|
2013-12-30 21:37:32 +08:00
|
|
|
int ret;
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-09-03 01:04:55 +08:00
|
|
|
if (Z_STRLEN_P(val) > 2 && numstr[0] == '0') {
|
|
|
|
if ((base == 0 || base == 16) && (numstr[1] == 'x' || numstr[1] == 'X')) {
|
|
|
|
base = 16;
|
|
|
|
skip_lead = 1;
|
|
|
|
} else if ((base == 0 || base == 2) && (numstr[1] == 'b' || numstr[1] == 'B')) {
|
|
|
|
base = 2;
|
|
|
|
skip_lead = 1;
|
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
|
|
|
|
2014-09-03 00:42:39 +08:00
|
|
|
ret = mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), (int) base);
|
2013-12-30 21:37:32 +08:00
|
|
|
if (-1 == ret) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING,
|
2013-12-30 21:37:32 +08:00
|
|
|
"Unable to convert variable to GMP - string is not an integer");
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
default:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING,
|
2013-12-30 21:37:32 +08:00
|
|
|
"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-11 07:12:57 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2015-02-05 01:12:56 +08:00
|
|
|
static void gmp_strval(zval *result, mpz_t gmpnum, int base) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
2014-09-03 00:42:39 +08:00
|
|
|
size_t num_len;
|
2014-05-07 00:44:28 +08:00
|
|
|
zend_string *str;
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
num_len = mpz_sizeinbase(gmpnum, abs(base));
|
|
|
|
if (mpz_sgn(gmpnum) < 0) {
|
|
|
|
num_len++;
|
|
|
|
}
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
str = zend_string_alloc(num_len, 0);
|
2014-05-07 00:44:28 +08:00
|
|
|
mpz_get_str(str->val, base, gmpnum);
|
2015-01-03 17:22:58 +08:00
|
|
|
|
|
|
|
/*
|
2013-06-17 23:49:24 +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...
|
|
|
|
*/
|
|
|
|
|
2014-05-07 00:44:28 +08:00
|
|
|
if (str->val[str->len - 1] == '\0') {
|
|
|
|
str->len--;
|
2013-06-17 23:49:24 +08:00
|
|
|
} else {
|
2014-05-07 00:44:28 +08:00
|
|
|
str->val[str->len] = '\0';
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2014-09-19 19:41:01 +08:00
|
|
|
ZVAL_NEW_STR(result, str);
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg) /* {{{ */
|
2013-06-17 23:49:24 +08:00
|
|
|
{
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
|
|
|
zend_bool use_si = 0;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long res;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
if (Z_TYPE_P(b_arg) == IS_LONG) {
|
2013-06-17 23:49:24 +08:00
|
|
|
use_si = 1;
|
|
|
|
temp_b.is_used = 0;
|
|
|
|
} else {
|
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (use_si) {
|
2014-08-26 01:24:55 +08:00
|
|
|
res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg));
|
2013-06-17 23:49:24 +08:00
|
|
|
} else {
|
|
|
|
res = mpz_cmp(gmpnum_a, gmpnum_b);
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETURN_LONG(res);
|
2013-06-17 23:49:24 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ gmp_zval_binary_ui_op
|
2000-11-27 02:36:16 +08:00
|
|
|
Execute GMP binary operation.
|
|
|
|
*/
|
2014-12-14 06:06:14 +08: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)
|
2001-08-08 01:57:55 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
|
2003-11-19 13:00:56 +08:00
|
|
|
int use_ui = 0;
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_temp_t temp_a, temp_b;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
|
2003-11-19 13:00:56 +08:00
|
|
|
use_ui = 1;
|
2013-06-17 23:49:24 +08:00
|
|
|
temp_b.is_used = 0;
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (check_b_zero) {
|
2005-04-25 20:18:50 +08:00
|
|
|
int b_is_zero = 0;
|
2013-06-17 23:49:24 +08:00
|
|
|
if (use_ui) {
|
2014-08-26 01:24:55 +08:00
|
|
|
b_is_zero = (Z_LVAL_P(b_arg) == 0);
|
2005-04-25 20:18:50 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
|
2005-04-25 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (b_is_zero) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Zero operand not allowed");
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2005-04-25 20:18:50 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2004-02-16 01:22:57 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2003-11-19 13:00:56 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (use_ui) {
|
2014-09-03 00:19:51 +08:00
|
|
|
gmp_ui_op(gmpnum_result, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_op(gmpnum_result, gmpnum_a, gmpnum_b);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ gmp_zval_binary_ui_op2
|
2000-11-27 02:36:16 +08:00
|
|
|
Execute GMP binary operation which returns 2 values.
|
|
|
|
*/
|
2014-12-14 06:06:14 +08: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)
|
2001-08-08 01:57:55 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2;
|
2003-11-19 13:00:56 +08:00
|
|
|
int use_ui = 0;
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_temp_t temp_a, temp_b;
|
2014-05-07 00:44:28 +08:00
|
|
|
zval result1, result2;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2003-11-19 13:00:56 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
|
2000-11-27 02:36:16 +08:00
|
|
|
/* use _ui function */
|
2003-11-19 13:00:56 +08:00
|
|
|
use_ui = 1;
|
2013-06-17 23:49:24 +08:00
|
|
|
temp_b.is_used = 0;
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (check_b_zero) {
|
2005-04-25 20:18:50 +08:00
|
|
|
int b_is_zero = 0;
|
2013-06-17 23:49:24 +08:00
|
|
|
if (use_ui) {
|
2014-08-26 01:24:55 +08:00
|
|
|
b_is_zero = (Z_LVAL_P(b_arg) == 0);
|
2005-04-25 20:18:50 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
|
2005-04-25 20:18:50 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (b_is_zero) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Zero operand not allowed");
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2005-04-25 20:18:50 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2004-02-16 01:22:57 +08:00
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_create(&result1, &gmpnum_result1);
|
|
|
|
gmp_create(&result2, &gmpnum_result2);
|
2014-05-07 00:44:28 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
array_init(return_value);
|
2014-05-07 00:44:28 +08:00
|
|
|
add_next_index_zval(return_value, &result1);
|
|
|
|
add_next_index_zval(return_value, &result2);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (use_ui) {
|
2014-09-03 00:19:51 +08:00
|
|
|
gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
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_binary_ui_op
|
|
|
|
*/
|
2013-06-17 23:49:24 +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, int check_b_zero)
|
2003-11-19 13:00:56 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero);
|
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
|
|
|
|
*/
|
2014-12-14 06:06:14 +08:00
|
|
|
static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op)
|
2001-08-08 01:57:55 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a;
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
gmp_op(gmpnum_result, gmpnum_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
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_zval_unary_ui_op
|
|
|
|
*/
|
2014-12-14 06:06:14 +08:00
|
|
|
static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op)
|
2003-11-19 13:00:56 +08:00
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_result;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-08-26 01:24:55 +08:00
|
|
|
gmp_op(gmpnum_result, zval_get_long(a_arg));
|
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_ui_op
|
2000-11-27 02:36:16 +08:00
|
|
|
Execute GMP unary operation.
|
|
|
|
*/
|
2003-11-19 13:00:56 +08:00
|
|
|
static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2007-11-01 08:46:13 +08:00
|
|
|
|
2014-12-14 06:06:14 +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
|
|
|
|
*/
|
2003-11-19 13:00:56 +08:00
|
|
|
static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_zval_unary_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_opl
|
|
|
|
*/
|
2003-11-19 13:00:56 +08:00
|
|
|
static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(gmp_op(gmpnum_a));
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
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
|
|
|
|
*/
|
2003-11-19 13:00:56 +08:00
|
|
|
static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2007-11-01 08:46:13 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(gmp_op(gmpnum_a, gmpnum_b));
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
2001-06-05 21:12:10 +08:00
|
|
|
/* }}} */
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *number_arg;
|
|
|
|
mpz_ptr gmpnumber;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long base = 0;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &number_arg, &base) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2014-09-29 02:39:19 +08:00
|
|
|
if (base && (base < 2 || base > GMP_MAX_BASE)) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Bad base for conversion: %pd (should be between 2 and %d)", base, GMP_MAX_BASE);
|
2007-11-01 08:46:13 +08:00
|
|
|
RETURN_FALSE;
|
2001-08-05 22:48:17 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnumber);
|
2014-12-14 06:06:14 +08:00
|
|
|
if (convert_to_gmp(gmpnumber, number_arg, base) == FAILURE) {
|
2013-06-17 23:49:24 +08:00
|
|
|
zval_dtor(return_value);
|
2000-11-27 02:36:16 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
int gmp_import_export_validate(zend_long size, zend_long options, int *order, int *endian)
|
2014-08-28 04:45:05 +08:00
|
|
|
{
|
|
|
|
if (size < 1) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING,
|
2014-09-03 21:57:28 +08:00
|
|
|
"Word size must be positive, %pd given", size);
|
2014-08-28 04:45:05 +08:00
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (options & (GMP_LSW_FIRST | GMP_MSW_FIRST)) {
|
|
|
|
case GMP_LSW_FIRST:
|
|
|
|
*order = -1;
|
|
|
|
break;
|
|
|
|
case GMP_MSW_FIRST:
|
|
|
|
case 0: /* default */
|
|
|
|
*order = 1;
|
|
|
|
break;
|
|
|
|
default:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING,
|
2014-08-28 04:45:05 +08:00
|
|
|
"Invalid options: Conflicting word orders");
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (options & (GMP_LITTLE_ENDIAN | GMP_BIG_ENDIAN | GMP_NATIVE_ENDIAN)) {
|
|
|
|
case GMP_LITTLE_ENDIAN:
|
|
|
|
*endian = -1;
|
|
|
|
break;
|
|
|
|
case GMP_BIG_ENDIAN:
|
|
|
|
*endian = 1;
|
|
|
|
break;
|
|
|
|
case GMP_NATIVE_ENDIAN:
|
|
|
|
case 0: /* default */
|
|
|
|
*endian = 0;
|
|
|
|
break;
|
|
|
|
default:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING,
|
2014-08-28 04:45:05 +08:00
|
|
|
"Invalid options: Conflicting word endianness");
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* {{{ proto GMP gmp_import(string data [, int word_size = 1, int options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN])
|
|
|
|
Imports a GMP number from a binary string */
|
|
|
|
ZEND_FUNCTION(gmp_import)
|
|
|
|
{
|
|
|
|
char *data;
|
2014-09-02 20:28:07 +08:00
|
|
|
size_t data_len;
|
|
|
|
zend_long size = 1;
|
2014-09-02 22:40:41 +08:00
|
|
|
zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
|
2014-08-28 04:45:05 +08:00
|
|
|
int order, endian;
|
|
|
|
mpz_ptr gmpnumber;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &data, &data_len, &size, &options) == FAILURE) {
|
2014-08-28 04:45:05 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (gmp_import_export_validate(size, options, &order, &endian) == FAILURE) {
|
2014-08-28 04:45:05 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((data_len % size) != 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING,
|
2014-08-28 04:45:05 +08:00
|
|
|
"Input length must be a multiple of word size");
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_RETVAL(gmpnumber);
|
|
|
|
|
|
|
|
mpz_import(gmpnumber, data_len / size, order, size, endian, 0, data);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto string gmp_export(GMP gmpnumber [, int word_size = 1, int options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN])
|
|
|
|
Exports a GMP number to a binary string */
|
|
|
|
ZEND_FUNCTION(gmp_export)
|
|
|
|
{
|
|
|
|
zval *gmpnumber_arg;
|
2014-09-02 20:28:07 +08:00
|
|
|
zend_long size = 1;
|
2014-09-02 22:40:41 +08:00
|
|
|
zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
|
2014-08-28 04:45:05 +08:00
|
|
|
int order, endian;
|
|
|
|
mpz_ptr gmpnumber;
|
|
|
|
gmp_temp_t temp_a;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &gmpnumber_arg, &size, &options) == FAILURE) {
|
2014-08-28 04:45:05 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (gmp_import_export_validate(size, options, &order, &endian) == FAILURE) {
|
2014-08-28 04:45:05 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnumber, gmpnumber_arg, temp_a);
|
|
|
|
|
|
|
|
if (mpz_sgn(gmpnumber) == 0) {
|
2014-09-02 20:28:07 +08:00
|
|
|
RETURN_EMPTY_STRING();
|
2014-08-28 04:45:05 +08:00
|
|
|
} else {
|
|
|
|
size_t bits_per_word = size * 8;
|
|
|
|
size_t count = (mpz_sizeinbase(gmpnumber, 2) + bits_per_word - 1) / bits_per_word;
|
|
|
|
size_t out_len = count * size;
|
|
|
|
|
2014-09-02 20:28:07 +08:00
|
|
|
zend_string *out_string = zend_string_alloc(out_len, 0);
|
|
|
|
mpz_export(out_string->val, NULL, order, size, endian, 0, gmpnumber);
|
|
|
|
out_string->val[out_len] = '\0';
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2014-09-02 20:28:07 +08:00
|
|
|
RETURN_STR(out_string);
|
2014-08-28 04:45:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_intval(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *gmpnumber_arg;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &gmpnumber_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (IS_GMP(gmpnumber_arg)) {
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(mpz_get_si(GET_GMP_FROM_ZVAL(gmpnumber_arg)));
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(zval_get_long(gmpnumber_arg));
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto string gmp_strval(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *gmpnumber_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long base = 10;
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &base) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2014-09-29 02:39:19 +08:00
|
|
|
/* Although the maximum base in general in GMP is 62, mpz_get_str()
|
2010-09-15 18:51:55 +08:00
|
|
|
* is explicitly limited to -36 when dealing with negative bases. */
|
2014-09-29 02:39:19 +08:00
|
|
|
if ((base < 2 && base > -2) || base > GMP_MAX_BASE || base < -36) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Bad base for conversion: %pd (should be between 2 and %d or -2 and -36)", base, GMP_MAX_BASE);
|
2000-12-05 22:17:38 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a);
|
|
|
|
|
2015-02-05 01:12:56 +08:00
|
|
|
gmp_strval(return_value, gmpnum, (int)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-11 07:12:57 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_add(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_ui_op(mpz_add, mpz_add_ui);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_sub(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_ui_op(mpz_sub, mpz_sub_ui);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_mul(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_ui_op(mpz_mul, mpz_mul_ui);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto array gmp_div_qr(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long round = GMP_ROUND_ZERO;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2003-11-19 13:00:56 +08:00
|
|
|
switch (round) {
|
2000-11-27 02:36:16 +08:00
|
|
|
case GMP_ROUND_ZERO:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
2013-06-17 23:49:24 +08:00
|
|
|
default:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Invalid rounding mode");
|
2013-06-17 23:49:24 +08:00
|
|
|
RETURN_FALSE;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_div_r(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long round = GMP_ROUND_ZERO;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2003-11-19 13:00:56 +08:00
|
|
|
switch (round) {
|
2000-11-27 02:36:16 +08:00
|
|
|
case GMP_ROUND_ZERO:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
2013-06-17 23:49:24 +08:00
|
|
|
default:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Invalid rounding mode");
|
2013-06-17 23:49:24 +08:00
|
|
|
RETURN_FALSE;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_div_q(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long round = GMP_ROUND_ZERO;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2003-11-19 13:00:56 +08:00
|
|
|
switch (round) {
|
2000-11-27 02:36:16 +08:00
|
|
|
case GMP_ROUND_ZERO:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_PLUSINF:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
|
|
|
case GMP_ROUND_MINUSINF:
|
2014-12-14 06:06:14 +08: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);
|
2000-11-27 02:36:16 +08:00
|
|
|
break;
|
2013-06-17 23:49:24 +08:00
|
|
|
default:
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Invalid rounding mode");
|
2013-06-17 23:49:24 +08:00
|
|
|
RETURN_FALSE;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_mod(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t) mpz_mod_ui);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_divexact(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_ui_op_no_zero(mpz_divexact, NULL);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_neg(mixed 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);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_abs(mixed 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);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
2005-03-01 21:09:33 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2005-03-01 21:09:33 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (IS_GMP(a_arg)) {
|
|
|
|
mpz_ptr gmpnum_tmp = GET_GMP_FROM_ZVAL(a_arg);
|
|
|
|
if (mpz_sgn(gmpnum_tmp) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
|
2005-03-01 21:09:33 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
} else {
|
2014-08-26 01:24:55 +08:00
|
|
|
if (zval_get_long(a_arg) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
|
2005-03-01 21:09:33 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2013-06-17 23:49:24 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_pow(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *base_arg;
|
|
|
|
mpz_ptr gmpnum_result, gmpnum_base;
|
|
|
|
gmp_temp_t temp_base;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long exp;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &base_arg, &exp) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 17:25:11 +08:00
|
|
|
if (exp < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Negative exponent not supported");
|
2000-11-27 02:36:16 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-08-26 01:24:55 +08:00
|
|
|
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-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
|
|
|
|
mpz_pow_ui(gmpnum_result, gmpnum_base, exp);
|
2007-11-01 17:34:18 +08:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_powm(mixed base, mixed exp, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *base_arg, *exp_arg, *mod_arg;
|
|
|
|
mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
|
2003-11-19 13:00:56 +08:00
|
|
|
int use_ui = 0;
|
2013-10-30 03:07:34 +08:00
|
|
|
gmp_temp_t temp_base, temp_exp, temp_mod;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base);
|
2003-11-19 13:00:56 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) {
|
2003-11-19 13:00:56 +08:00
|
|
|
use_ui = 1;
|
2013-06-17 23:49:24 +08:00
|
|
|
temp_exp.is_used = 0;
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base);
|
|
|
|
if (mpz_sgn(gmpnum_exp) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Second parameter cannot be less than 0");
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
|
|
|
FREE_GMP_TEMP(temp_exp);
|
2005-03-01 21:09:33 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (!mpz_cmp_ui(gmpnum_mod, 0)) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Modulus may not be zero");
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
2014-09-05 02:55:09 +08:00
|
|
|
FREE_GMP_TEMP(temp_exp);
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_mod);
|
2004-02-16 01:22:57 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2003-11-19 13:00:56 +08:00
|
|
|
if (use_ui) {
|
2014-08-26 01:24:55 +08:00
|
|
|
mpz_powm_ui(gmpnum_result, gmpnum_base, (zend_ulong) Z_LVAL_P(exp_arg), gmpnum_mod);
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
|
2007-11-01 17:34:18 +08:00
|
|
|
FREE_GMP_TEMP(temp_exp);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_base);
|
|
|
|
FREE_GMP_TEMP(temp_mod);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_sqrt(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a;
|
2005-03-01 21:09:33 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2005-03-01 21:09:33 +08:00
|
|
|
}
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2005-03-01 21:09:33 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
if (mpz_sgn(gmpnum_a) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2005-03-01 21:09:33 +08:00
|
|
|
RETURN_FALSE;
|
2014-08-28 04:45:05 +08:00
|
|
|
}
|
2005-03-01 21:09:33 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
mpz_sqrt(gmpnum_result, gmpnum_a);
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto array gmp_sqrtrem(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
|
|
|
|
gmp_temp_t temp_a;
|
2014-05-07 00:44:28 +08:00
|
|
|
zval result1, result2;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 23:49:24 +08:00
|
|
|
|
|
|
|
if (mpz_sgn(gmpnum_a) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Number has to be greater than or equal to 0");
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2005-03-01 21:09:33 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2015-01-03 17:22:58 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_create(&result1, &gmpnum_result1);
|
|
|
|
gmp_create(&result2, &gmpnum_result2);
|
2014-05-07 00:44:28 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
array_init(return_value);
|
2014-05-07 00:44:28 +08:00
|
|
|
add_next_index_zval(return_value, &result1);
|
|
|
|
add_next_index_zval(return_value, &result2);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a);
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-29 06:42:23 +08:00
|
|
|
/* {{{ proto GMP gmp_root(mixed a, int nth)
|
|
|
|
Takes integer part of nth root */
|
|
|
|
ZEND_FUNCTION(gmp_root)
|
|
|
|
{
|
|
|
|
zval *a_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long nth;
|
2013-11-29 06:42:23 +08:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
|
2013-11-29 06:42:23 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nth <= 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "The root must be positive");
|
2013-11-29 06:42:23 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
|
|
|
|
if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Can't take even root of negative number");
|
2013-11-29 06:42:23 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-09-03 00:19:51 +08:00
|
|
|
mpz_root(gmpnum_result, gmpnum_a, (gmp_ulong) nth);
|
2013-11-29 06:42:23 +08:00
|
|
|
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;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long nth;
|
2013-11-29 06:42:23 +08:00
|
|
|
mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
|
|
|
|
gmp_temp_t temp_a;
|
2014-05-07 00:44:28 +08:00
|
|
|
zval result1, result2;
|
2013-11-29 06:42:23 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
|
2013-11-29 06:42:23 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nth <= 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "The root must be positive");
|
2013-11-29 06:42:23 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
|
|
|
|
if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Can't take even root of negative number");
|
2013-11-29 06:42:23 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_create(&result1, &gmpnum_result1);
|
|
|
|
gmp_create(&result2, &gmpnum_result2);
|
2014-05-07 00:44:28 +08:00
|
|
|
|
2013-11-29 06:42:23 +08:00
|
|
|
array_init(return_value);
|
2014-05-07 00:44:28 +08:00
|
|
|
add_next_index_zval(return_value, &result1);
|
|
|
|
add_next_index_zval(return_value, &result2);
|
2013-11-29 06:42:23 +08:00
|
|
|
|
2014-09-03 00:19:51 +08:00
|
|
|
mpz_rootrem(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) nth);
|
2014-08-28 04:45:05 +08:00
|
|
|
|
2013-11-29 06:42:23 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto bool gmp_perfect_square(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0));
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_prob_prime(mixed a[, int reps])
|
2000-12-06 22:10:40 +08:00
|
|
|
Checks if a is "probably prime" */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_prob_prime)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *gmpnumber_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long reps = 10;
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_temp_t temp_a;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &reps) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, reps));
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_gcd(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t) mpz_gcd_ui);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto array gmp_gcdext(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08: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-07 00:44:28 +08:00
|
|
|
zval result_g, result_s, result_t;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_create(&result_g, &gmpnum_g);
|
|
|
|
gmp_create(&result_s, &gmpnum_s);
|
|
|
|
gmp_create(&result_t, &gmpnum_t);
|
2014-05-07 00:44:28 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
array_init(return_value);
|
2014-05-07 00:44:28 +08: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-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b);
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_invert(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
|
|
|
mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
2007-11-01 08:46:13 +08:00
|
|
|
int res;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b);
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
2013-06-17 23:49:24 +08:00
|
|
|
if (!res) {
|
|
|
|
zval_dtor(return_value);
|
2000-11-27 02:36:16 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_jacobi(mixed a, mixed 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
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_legendre(mixed a, mixed 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
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_cmp(mixed a, mixed b)
|
2000-12-01 23:25:22 +08:00
|
|
|
Compares two numbers */
|
2000-11-27 02:36:16 +08:00
|
|
|
ZEND_FUNCTION(gmp_cmp)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg, *b_arg;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_cmp(return_value, a_arg, b_arg);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_sign(mixed 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)
|
|
|
|
{
|
2013-11-23 19:54:20 +08:00
|
|
|
/* Can't use gmp_unary_opl here, because mpz_sgn is a macro */
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
2013-11-23 19:54:20 +08:00
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(mpz_sgn(gmpnum_a));
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
static void gmp_init_random(void)
|
2014-09-24 05:12:23 +08:00
|
|
|
{
|
|
|
|
if (!GMPG(rand_initialized)) {
|
|
|
|
/* Initialize */
|
|
|
|
gmp_randinit_mt(GMPG(rand_state));
|
|
|
|
/* Seed */
|
|
|
|
gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
|
|
|
|
|
|
|
|
GMPG(rand_initialized) = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP 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)
|
|
|
|
{
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long limiter = 20;
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_result;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &limiter) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_init_random();
|
2003-11-19 12:44:06 +08:00
|
|
|
|
2010-02-23 19:07:39 +08:00
|
|
|
#ifdef GMP_LIMB_BITS
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS);
|
2010-02-23 19:07:39 +08:00
|
|
|
#else
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB);
|
2010-02-23 19:07:39 +08:00
|
|
|
#endif
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-10-20 00:25:05 +08:00
|
|
|
/* {{{ proto GMP gmp_random_seed(mixed seed)
|
|
|
|
Seed the RNG */
|
|
|
|
ZEND_FUNCTION(gmp_random_seed)
|
|
|
|
{
|
|
|
|
zval *seed;
|
|
|
|
mpz_ptr gmpnum_seed;
|
|
|
|
gmp_temp_t temp_a;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &seed) == FAILURE) {
|
2014-10-20 00:25:05 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_init_random();
|
2014-10-20 00:25:05 +08:00
|
|
|
|
|
|
|
if (Z_TYPE_P(seed) == IS_LONG && Z_LVAL_P(seed) >= 0) {
|
|
|
|
gmp_randseed_ui(GMPG(rand_state), Z_LVAL_P(seed));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_seed, seed, temp_a);
|
|
|
|
|
|
|
|
gmp_randseed(GMPG(rand_state), gmpnum_seed);
|
|
|
|
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2014-09-24 05:12:23 +08:00
|
|
|
/* {{{ proto GMP gmp_random_bits(int bits)
|
|
|
|
Gets a random number in the range 0 to (2 ** n) - 1 */
|
|
|
|
ZEND_FUNCTION(gmp_random_bits)
|
|
|
|
{
|
2014-10-22 23:46:13 +08:00
|
|
|
zend_long bits;
|
2014-09-24 05:12:23 +08:00
|
|
|
mpz_ptr gmpnum_result;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &bits) == FAILURE) {
|
2014-09-24 05:12:23 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-09-24 05:54:40 +08:00
|
|
|
if (bits <= 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "The number of bits must be positive");
|
2014-09-25 05:01:09 +08:00
|
|
|
RETURN_FALSE;
|
2014-09-24 05:12:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_init_random();
|
2014-09-24 05:12:23 +08:00
|
|
|
|
|
|
|
mpz_urandomb(gmpnum_result, GMPG(rand_state), bits);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
|
|
|
/* {{{ proto GMP gmp_random_range(mixed min, mixed max)
|
|
|
|
Gets a random number in the range min to max */
|
|
|
|
ZEND_FUNCTION(gmp_random_range)
|
|
|
|
{
|
|
|
|
zval *min_arg, *max_arg;
|
|
|
|
mpz_ptr gmpnum_min, gmpnum_max, gmpnum_result;
|
|
|
|
gmp_temp_t temp_a, temp_b;
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &min_arg, &max_arg) == FAILURE) {
|
2014-09-24 05:12:23 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
gmp_init_random();
|
2014-09-25 05:01:09 +08:00
|
|
|
|
|
|
|
FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a);
|
|
|
|
|
|
|
|
if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
|
|
|
|
if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "The minimum value must be less than the maximum value");
|
2014-09-25 05:01:09 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
|
|
|
|
|
|
|
if (Z_LVAL_P(min_arg)) {
|
|
|
|
mpz_sub_ui(gmpnum_max, gmpnum_max, Z_LVAL_P(min_arg));
|
|
|
|
}
|
|
|
|
|
|
|
|
mpz_add_ui(gmpnum_max, gmpnum_max, 1);
|
|
|
|
mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_max);
|
|
|
|
|
|
|
|
if (Z_LVAL_P(min_arg)) {
|
|
|
|
mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
|
|
|
|
}
|
2014-09-24 05:12:23 +08:00
|
|
|
|
2014-09-24 14:56:46 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2014-09-25 05:01:09 +08:00
|
|
|
|
2014-09-24 14:56:46 +08:00
|
|
|
}
|
2014-09-25 05:01:09 +08:00
|
|
|
else {
|
|
|
|
FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a);
|
2014-09-24 14:56:46 +08:00
|
|
|
|
2014-09-25 05:01:09 +08:00
|
|
|
if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "The minimum value must be less than the maximum value");
|
2014-09-25 05:01:09 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2014-09-24 05:12:23 +08:00
|
|
|
|
2014-09-25 05:01:09 +08:00
|
|
|
INIT_GMP_RETVAL(gmpnum_result);
|
2014-09-24 05:12:23 +08:00
|
|
|
|
2014-09-25 05:01:09 +08:00
|
|
|
mpz_sub(gmpnum_max, gmpnum_max, gmpnum_min);
|
|
|
|
mpz_add_ui(gmpnum_max, gmpnum_max, 1);
|
|
|
|
mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_max);
|
|
|
|
mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
|
|
|
|
|
|
|
|
FREE_GMP_TEMP(temp_b);
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
|
|
|
}
|
2014-09-24 05:12:23 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_and(mixed a, mixed 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);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_or(mixed a, mixed 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);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_com(mixed 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);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_nextprime(mixed a)
|
2006-07-18 22:54:32 +08:00
|
|
|
Finds next prime of a */
|
|
|
|
ZEND_FUNCTION(gmp_nextprime)
|
|
|
|
{
|
|
|
|
gmp_unary_op(mpz_nextprime);
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto GMP gmp_xor(mixed a, mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
gmp_binary_op(mpz_xor);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
/* {{{ proto void gmp_setbit(GMP 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long index;
|
2007-11-01 17:25:11 +08:00
|
|
|
zend_bool set = 1;
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_a;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) {
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-04-19 04:36:54 +08:00
|
|
|
if (index < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Index must be greater than or equal to zero");
|
2014-09-25 05:55:13 +08:00
|
|
|
RETURN_FALSE;
|
2007-04-19 04:36:54 +08:00
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
|
|
|
|
|
2003-11-19 13:00:56 +08:00
|
|
|
if (set) {
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_setbit(gmpnum_a, index);
|
2000-11-27 02:36:16 +08:00
|
|
|
} else {
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_clrbit(gmpnum_a, index);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-11-29 07:00:41 +08:00
|
|
|
/* {{{ proto void gmp_clrbit(GMP 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long index;
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_a;
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &a_arg, gmp_ce, &index) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
|
2007-04-19 04:36:54 +08:00
|
|
|
if (index < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Index must be greater than or equal to zero");
|
2014-09-25 05:55:13 +08:00
|
|
|
RETURN_FALSE;
|
2007-04-19 04:36:54 +08:00
|
|
|
}
|
2000-11-27 02:36:16 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
|
|
|
|
mpz_clrbit(gmpnum_a, index);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto bool gmp_testbit(mixed a, int index)
|
2007-11-02 01:51:34 +08:00
|
|
|
Tests if bit is set in a */
|
|
|
|
ZEND_FUNCTION(gmp_testbit)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long index;
|
2013-06-17 23:49:24 +08:00
|
|
|
mpz_ptr gmpnum_a;
|
2014-03-10 19:06:40 +08:00
|
|
|
gmp_temp_t temp_a;
|
2007-11-02 01:51:34 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &index) == FAILURE){
|
2007-11-02 01:51:34 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Index must be greater than or equal to zero");
|
2007-11-02 01:51:34 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2014-03-10 19:06:40 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
RETVAL_BOOL(mpz_tstbit(gmpnum_a, index));
|
|
|
|
FREE_GMP_TEMP(temp_a);
|
2007-11-02 01:51:34 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_popcount(mixed 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)
|
|
|
|
{
|
2013-11-23 19:54:20 +08:00
|
|
|
gmp_unary_opl((gmp_unary_opl_t) mpz_popcount);
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_hamdist(mixed a, mixed 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)
|
|
|
|
{
|
2013-11-23 19:54:20 +08:00
|
|
|
gmp_binary_opl((gmp_binary_opl_t) mpz_hamdist);
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_scan0(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long start;
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
if (start < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Starting index must be greater than or equal to zero");
|
2007-04-19 04:53:28 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(mpz_scan0(gmpnum_a, start));
|
2007-11-01 08:46:13 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
/* {{{ proto int gmp_scan1(mixed 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)
|
|
|
|
{
|
2013-06-17 23:49:24 +08:00
|
|
|
zval *a_arg;
|
|
|
|
mpz_ptr gmpnum_a;
|
|
|
|
gmp_temp_t temp_a;
|
2014-08-26 01:24:55 +08:00
|
|
|
zend_long start;
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2014-12-14 06:06:14 +08:00
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
|
2007-11-01 08:46:13 +08:00
|
|
|
return;
|
2000-11-29 23:49:18 +08:00
|
|
|
}
|
|
|
|
|
2007-11-01 08:46:13 +08:00
|
|
|
if (start < 0) {
|
2014-12-14 06:06:14 +08:00
|
|
|
php_error_docref(NULL, E_WARNING, "Starting index must be greater than or equal to zero");
|
2007-04-19 04:53:28 +08:00
|
|
|
RETURN_FALSE;
|
|
|
|
}
|
2000-11-29 23:49:18 +08:00
|
|
|
|
2013-06-17 23:49:24 +08:00
|
|
|
FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a);
|
2001-07-31 13:44:11 +08:00
|
|
|
|
2014-08-26 01:24:55 +08:00
|
|
|
RETVAL_LONG(mpz_scan1(gmpnum_a, start));
|
2013-06-17 23:49:24 +08:00
|
|
|
FREE_GMP_TEMP(temp_a);
|
2000-11-27 02:36:16 +08:00
|
|
|
}
|
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:
|
2006-06-15 05:36:10 +08:00
|
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
|
|
* vim<600: noet sw=4 ts=4
|
2000-11-27 02:36:16 +08:00
|
|
|
*/
|