Return to gmp.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / ext / gmp |
1.1 ! misho 1: /* ! 2: +----------------------------------------------------------------------+ ! 3: | PHP Version 5 | ! 4: +----------------------------------------------------------------------+ ! 5: | Copyright (c) 1997-2012 The PHP Group | ! 6: +----------------------------------------------------------------------+ ! 7: | This source file is subject to version 3.01 of the PHP license, | ! 8: | that is bundled with this package in the file LICENSE, and is | ! 9: | available through the world-wide-web at the following url: | ! 10: | http://www.php.net/license/3_01.txt | ! 11: | If you did not receive a copy of the PHP license and are unable to | ! 12: | obtain it through the world-wide-web, please send a note to | ! 13: | license@php.net so we can mail you a copy immediately. | ! 14: +----------------------------------------------------------------------+ ! 15: | Author: Stanislav Malyshev <stas@php.net> | ! 16: +----------------------------------------------------------------------+ ! 17: */ ! 18: ! 19: #ifdef HAVE_CONFIG_H ! 20: #include "config.h" ! 21: #endif ! 22: ! 23: #include "php.h" ! 24: #include "php_ini.h" ! 25: #include "php_gmp.h" ! 26: #include "ext/standard/info.h" ! 27: ! 28: #if HAVE_GMP ! 29: ! 30: #include <gmp.h> ! 31: ! 32: /* Needed for gmp_random() */ ! 33: #include "ext/standard/php_rand.h" ! 34: #include "ext/standard/php_lcg.h" ! 35: #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) ! 36: ! 37: /* True global resources - no need for thread safety here */ ! 38: static int le_gmp; ! 39: ! 40: /* {{{ arginfo */ ! 41: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1) ! 42: ZEND_ARG_INFO(0, number) ! 43: ZEND_ARG_INFO(0, base) ! 44: ZEND_END_ARG_INFO() ! 45: ! 46: ZEND_BEGIN_ARG_INFO(arginfo_gmp_intval, 0) ! 47: ZEND_ARG_INFO(0, gmpnumber) ! 48: ZEND_END_ARG_INFO() ! 49: ! 50: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_strval, 0, 0, 1) ! 51: ZEND_ARG_INFO(0, gmpnumber) ! 52: ZEND_ARG_INFO(0, base) ! 53: ZEND_END_ARG_INFO() ! 54: ! 55: ZEND_BEGIN_ARG_INFO(arginfo_gmp_add, 0) ! 56: ZEND_ARG_INFO(0, a) ! 57: ZEND_ARG_INFO(0, b) ! 58: ZEND_END_ARG_INFO() ! 59: ! 60: ZEND_BEGIN_ARG_INFO(arginfo_gmp_sub, 0) ! 61: ZEND_ARG_INFO(0, a) ! 62: ZEND_ARG_INFO(0, b) ! 63: ZEND_END_ARG_INFO() ! 64: ! 65: ZEND_BEGIN_ARG_INFO(arginfo_gmp_mul, 0) ! 66: ZEND_ARG_INFO(0, a) ! 67: ZEND_ARG_INFO(0, b) ! 68: ZEND_END_ARG_INFO() ! 69: ! 70: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_qr, 0, 0, 2) ! 71: ZEND_ARG_INFO(0, a) ! 72: ZEND_ARG_INFO(0, b) ! 73: ZEND_ARG_INFO(0, round) ! 74: ZEND_END_ARG_INFO() ! 75: ! 76: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_r, 0, 0, 2) ! 77: ZEND_ARG_INFO(0, a) ! 78: ZEND_ARG_INFO(0, b) ! 79: ZEND_ARG_INFO(0, round) ! 80: ZEND_END_ARG_INFO() ! 81: ! 82: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_div_q, 0, 0, 2) ! 83: ZEND_ARG_INFO(0, a) ! 84: ZEND_ARG_INFO(0, b) ! 85: ZEND_ARG_INFO(0, round) ! 86: ZEND_END_ARG_INFO() ! 87: ! 88: ZEND_BEGIN_ARG_INFO(arginfo_gmp_mod, 0) ! 89: ZEND_ARG_INFO(0, a) ! 90: ZEND_ARG_INFO(0, b) ! 91: ZEND_END_ARG_INFO() ! 92: ! 93: ZEND_BEGIN_ARG_INFO(arginfo_gmp_divexact, 0) ! 94: ZEND_ARG_INFO(0, a) ! 95: ZEND_ARG_INFO(0, b) ! 96: ZEND_END_ARG_INFO() ! 97: ! 98: ZEND_BEGIN_ARG_INFO(arginfo_gmp_neg, 0) ! 99: ZEND_ARG_INFO(0, a) ! 100: ZEND_END_ARG_INFO() ! 101: ! 102: ZEND_BEGIN_ARG_INFO(arginfo_gmp_abs, 0) ! 103: ZEND_ARG_INFO(0, a) ! 104: ZEND_END_ARG_INFO() ! 105: ! 106: ZEND_BEGIN_ARG_INFO(arginfo_gmp_fact, 0) ! 107: ZEND_ARG_INFO(0, a) ! 108: ZEND_END_ARG_INFO() ! 109: ! 110: ZEND_BEGIN_ARG_INFO(arginfo_gmp_pow, 0) ! 111: ZEND_ARG_INFO(0, base) ! 112: ZEND_ARG_INFO(0, exp) ! 113: ZEND_END_ARG_INFO() ! 114: ! 115: ZEND_BEGIN_ARG_INFO(arginfo_gmp_powm, 0) ! 116: ZEND_ARG_INFO(0, base) ! 117: ZEND_ARG_INFO(0, exp) ! 118: ZEND_ARG_INFO(0, mod) ! 119: ZEND_END_ARG_INFO() ! 120: ! 121: ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrt, 0) ! 122: ZEND_ARG_INFO(0, a) ! 123: ZEND_END_ARG_INFO() ! 124: ! 125: ZEND_BEGIN_ARG_INFO(arginfo_gmp_sqrtrem, 0) ! 126: ZEND_ARG_INFO(0, a) ! 127: ZEND_END_ARG_INFO() ! 128: ! 129: ZEND_BEGIN_ARG_INFO(arginfo_gmp_perfect_square, 0) ! 130: ZEND_ARG_INFO(0, a) ! 131: ZEND_END_ARG_INFO() ! 132: ! 133: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_prob_prime, 0, 0, 1) ! 134: ZEND_ARG_INFO(0, a) ! 135: ZEND_ARG_INFO(0, reps) ! 136: ZEND_END_ARG_INFO() ! 137: ! 138: ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcd, 0) ! 139: ZEND_ARG_INFO(0, a) ! 140: ZEND_ARG_INFO(0, b) ! 141: ZEND_END_ARG_INFO() ! 142: ! 143: ZEND_BEGIN_ARG_INFO(arginfo_gmp_gcdext, 0) ! 144: ZEND_ARG_INFO(0, a) ! 145: ZEND_ARG_INFO(0, b) ! 146: ZEND_END_ARG_INFO() ! 147: ! 148: ZEND_BEGIN_ARG_INFO(arginfo_gmp_invert, 0) ! 149: ZEND_ARG_INFO(0, a) ! 150: ZEND_ARG_INFO(0, b) ! 151: ZEND_END_ARG_INFO() ! 152: ! 153: ZEND_BEGIN_ARG_INFO(arginfo_gmp_jacobi, 0) ! 154: ZEND_ARG_INFO(0, a) ! 155: ZEND_ARG_INFO(0, b) ! 156: ZEND_END_ARG_INFO() ! 157: ! 158: ZEND_BEGIN_ARG_INFO(arginfo_gmp_legendre, 0) ! 159: ZEND_ARG_INFO(0, a) ! 160: ZEND_ARG_INFO(0, b) ! 161: ZEND_END_ARG_INFO() ! 162: ! 163: ZEND_BEGIN_ARG_INFO(arginfo_gmp_cmp, 0) ! 164: ZEND_ARG_INFO(0, a) ! 165: ZEND_ARG_INFO(0, b) ! 166: ZEND_END_ARG_INFO() ! 167: ! 168: ZEND_BEGIN_ARG_INFO(arginfo_gmp_sign, 0) ! 169: ZEND_ARG_INFO(0, a) ! 170: ZEND_END_ARG_INFO() ! 171: ! 172: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_random, 0, 0, 0) ! 173: ZEND_ARG_INFO(0, limiter) ! 174: ZEND_END_ARG_INFO() ! 175: ! 176: ZEND_BEGIN_ARG_INFO(arginfo_gmp_and, 0) ! 177: ZEND_ARG_INFO(0, a) ! 178: ZEND_ARG_INFO(0, b) ! 179: ZEND_END_ARG_INFO() ! 180: ! 181: ZEND_BEGIN_ARG_INFO(arginfo_gmp_or, 0) ! 182: ZEND_ARG_INFO(0, a) ! 183: ZEND_ARG_INFO(0, b) ! 184: ZEND_END_ARG_INFO() ! 185: ! 186: ZEND_BEGIN_ARG_INFO(arginfo_gmp_com, 0) ! 187: ZEND_ARG_INFO(0, a) ! 188: ZEND_END_ARG_INFO() ! 189: ! 190: ZEND_BEGIN_ARG_INFO(arginfo_gmp_xor, 0) ! 191: ZEND_ARG_INFO(0, a) ! 192: ZEND_ARG_INFO(0, b) ! 193: ZEND_END_ARG_INFO() ! 194: ! 195: ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_setbit, 0, 0, 2) ! 196: ZEND_ARG_INFO(1, a) ! 197: ZEND_ARG_INFO(0, index) ! 198: ZEND_ARG_INFO(0, set_clear) ! 199: ZEND_END_ARG_INFO() ! 200: ! 201: ZEND_BEGIN_ARG_INFO(arginfo_gmp_clrbit, 0) ! 202: ZEND_ARG_INFO(1, a) ! 203: ZEND_ARG_INFO(0, index) ! 204: ZEND_END_ARG_INFO() ! 205: ! 206: ZEND_BEGIN_ARG_INFO(arginfo_gmp_testbit, 0) ! 207: ZEND_ARG_INFO(0, a) ! 208: ZEND_ARG_INFO(0, index) ! 209: ZEND_END_ARG_INFO() ! 210: ! 211: ZEND_BEGIN_ARG_INFO(arginfo_gmp_popcount, 0) ! 212: ZEND_ARG_INFO(0, a) ! 213: ZEND_END_ARG_INFO() ! 214: ! 215: ZEND_BEGIN_ARG_INFO(arginfo_gmp_hamdist, 0) ! 216: ZEND_ARG_INFO(0, a) ! 217: ZEND_ARG_INFO(0, b) ! 218: ZEND_END_ARG_INFO() ! 219: ! 220: ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan0, 0) ! 221: ZEND_ARG_INFO(0, a) ! 222: ZEND_ARG_INFO(0, start) ! 223: ZEND_END_ARG_INFO() ! 224: ! 225: ZEND_BEGIN_ARG_INFO(arginfo_gmp_scan1, 0) ! 226: ZEND_ARG_INFO(0, a) ! 227: ZEND_ARG_INFO(0, start) ! 228: ZEND_END_ARG_INFO() ! 229: ! 230: ZEND_BEGIN_ARG_INFO(arginfo_gmp_nextprime, 0) ! 231: ZEND_ARG_INFO(0, a) ! 232: ZEND_END_ARG_INFO() ! 233: ! 234: /* }}} */ ! 235: ! 236: ZEND_DECLARE_MODULE_GLOBALS(gmp) ! 237: static ZEND_GINIT_FUNCTION(gmp); ! 238: ! 239: /* {{{ gmp_functions[] ! 240: */ ! 241: const zend_function_entry gmp_functions[] = { ! 242: ZEND_FE(gmp_init, arginfo_gmp_init) ! 243: ZEND_FE(gmp_intval, arginfo_gmp_intval) ! 244: ZEND_FE(gmp_strval, arginfo_gmp_strval) ! 245: ZEND_FE(gmp_add, arginfo_gmp_add) ! 246: ZEND_FE(gmp_sub, arginfo_gmp_sub) ! 247: ZEND_FE(gmp_mul, arginfo_gmp_mul) ! 248: ZEND_FE(gmp_div_qr, arginfo_gmp_div_qr) ! 249: ZEND_FE(gmp_div_q, arginfo_gmp_div_q) ! 250: ZEND_FE(gmp_div_r, arginfo_gmp_div_r) ! 251: ZEND_FALIAS(gmp_div, gmp_div_q, arginfo_gmp_div_q) ! 252: ZEND_FE(gmp_mod, arginfo_gmp_mod) ! 253: ZEND_FE(gmp_divexact, arginfo_gmp_divexact) ! 254: ZEND_FE(gmp_neg, arginfo_gmp_neg) ! 255: ZEND_FE(gmp_abs, arginfo_gmp_abs) ! 256: ZEND_FE(gmp_fact, arginfo_gmp_fact) ! 257: ZEND_FE(gmp_sqrt, arginfo_gmp_sqrt) ! 258: ZEND_FE(gmp_sqrtrem, arginfo_gmp_sqrtrem) ! 259: ZEND_FE(gmp_pow, arginfo_gmp_pow) ! 260: ZEND_FE(gmp_powm, arginfo_gmp_powm) ! 261: ZEND_FE(gmp_perfect_square, arginfo_gmp_perfect_square) ! 262: ZEND_FE(gmp_prob_prime, arginfo_gmp_prob_prime) ! 263: ZEND_FE(gmp_gcd, arginfo_gmp_gcd) ! 264: ZEND_FE(gmp_gcdext, arginfo_gmp_gcdext) ! 265: ZEND_FE(gmp_invert, arginfo_gmp_invert) ! 266: ZEND_FE(gmp_jacobi, arginfo_gmp_jacobi) ! 267: ZEND_FE(gmp_legendre, arginfo_gmp_legendre) ! 268: ZEND_FE(gmp_cmp, arginfo_gmp_cmp) ! 269: ZEND_FE(gmp_sign, arginfo_gmp_sign) ! 270: ZEND_FE(gmp_random, arginfo_gmp_random) ! 271: ZEND_FE(gmp_and, arginfo_gmp_and) ! 272: ZEND_FE(gmp_or, arginfo_gmp_or) ! 273: ZEND_FE(gmp_com, arginfo_gmp_com) ! 274: ZEND_FE(gmp_xor, arginfo_gmp_xor) ! 275: ZEND_FE(gmp_setbit, arginfo_gmp_setbit) ! 276: ZEND_FE(gmp_clrbit, arginfo_gmp_clrbit) ! 277: ZEND_FE(gmp_scan0, arginfo_gmp_scan0) ! 278: ZEND_FE(gmp_scan1, arginfo_gmp_scan1) ! 279: ZEND_FE(gmp_testbit,arginfo_gmp_testbit) ! 280: ZEND_FE(gmp_popcount, arginfo_gmp_popcount) ! 281: ZEND_FE(gmp_hamdist, arginfo_gmp_hamdist) ! 282: ZEND_FE(gmp_nextprime, arginfo_gmp_nextprime) ! 283: PHP_FE_END ! 284: }; ! 285: /* }}} */ ! 286: ! 287: /* {{{ gmp_module_entry ! 288: */ ! 289: zend_module_entry gmp_module_entry = { ! 290: STANDARD_MODULE_HEADER, ! 291: "gmp", ! 292: gmp_functions, ! 293: ZEND_MODULE_STARTUP_N(gmp), ! 294: NULL, ! 295: NULL, ! 296: ZEND_MODULE_DEACTIVATE_N(gmp), ! 297: ZEND_MODULE_INFO_N(gmp), ! 298: NO_VERSION_YET, ! 299: ZEND_MODULE_GLOBALS(gmp), ! 300: ZEND_GINIT(gmp), ! 301: NULL, ! 302: NULL, ! 303: STANDARD_MODULE_PROPERTIES_EX ! 304: }; ! 305: /* }}} */ ! 306: ! 307: #ifdef COMPILE_DL_GMP ! 308: ZEND_GET_MODULE(gmp) ! 309: #endif ! 310: ! 311: static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); ! 312: ! 313: #define GMP_RESOURCE_NAME "GMP integer" ! 314: ! 315: #define GMP_ROUND_ZERO 0 ! 316: #define GMP_ROUND_PLUSINF 1 ! 317: #define GMP_ROUND_MINUSINF 2 ! 318: ! 319: /* The maximum base for input and output conversions is 62 from GMP 4.2 ! 320: * onwards. */ ! 321: #if (__GNU_MP_VERSION >= 5) || (__GNU_MP_VERSION >= 4 && __GNU_MP_VERSION_MINOR >= 2) ! 322: # define MAX_BASE 62 ! 323: #else ! 324: # define MAX_BASE 36 ! 325: #endif ! 326: ! 327: /* {{{ gmp_emalloc ! 328: */ ! 329: static void *gmp_emalloc(size_t size) ! 330: { ! 331: return emalloc(size); ! 332: } ! 333: /* }}} */ ! 334: ! 335: /* {{{ gmp_erealloc ! 336: */ ! 337: static void *gmp_erealloc(void *ptr, size_t old_size, size_t new_size) ! 338: { ! 339: return erealloc(ptr, new_size); ! 340: } ! 341: /* }}} */ ! 342: ! 343: /* {{{ gmp_efree ! 344: */ ! 345: static void gmp_efree(void *ptr, size_t size) ! 346: { ! 347: efree(ptr); ! 348: } ! 349: /* }}} */ ! 350: ! 351: /* {{{ ZEND_GINIT_FUNCTION ! 352: */ ! 353: static ZEND_GINIT_FUNCTION(gmp) ! 354: { ! 355: gmp_globals->rand_initialized = 0; ! 356: } ! 357: /* }}} */ ! 358: ! 359: /* {{{ ZEND_MINIT_FUNCTION ! 360: */ ! 361: ZEND_MODULE_STARTUP_D(gmp) ! 362: { ! 363: le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number); ! 364: REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT); ! 365: REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT); ! 366: REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT); ! 367: #ifdef mpir_version ! 368: REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT); ! 369: #endif ! 370: REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT); ! 371: ! 372: mp_set_memory_functions(gmp_emalloc, gmp_erealloc, gmp_efree); ! 373: ! 374: return SUCCESS; ! 375: } ! 376: /* }}} */ ! 377: ! 378: /* {{{ ZEND_RSHUTDOWN_FUNCTION ! 379: */ ! 380: ZEND_MODULE_DEACTIVATE_D(gmp) ! 381: { ! 382: if (GMPG(rand_initialized)) { ! 383: gmp_randclear(GMPG(rand_state)); ! 384: GMPG(rand_initialized) = 0; ! 385: } ! 386: ! 387: return SUCCESS; ! 388: } ! 389: /* }}} */ ! 390: ! 391: /* {{{ ZEND_MINFO_FUNCTION ! 392: */ ! 393: ZEND_MODULE_INFO_D(gmp) ! 394: { ! 395: php_info_print_table_start(); ! 396: php_info_print_table_row(2, "gmp support", "enabled"); ! 397: #ifdef mpir_version ! 398: php_info_print_table_row(2, "MPIR version", mpir_version); ! 399: #else ! 400: php_info_print_table_row(2, "GMP version", gmp_version); ! 401: #endif ! 402: php_info_print_table_end(); ! 403: } ! 404: /* }}} */ ! 405: ! 406: /* Fetch zval to be GMP number. ! 407: Initially, zval can be also number or string */ ! 408: #define FETCH_GMP_ZVAL(gmpnumber, zval, tmp_resource) \ ! 409: if (Z_TYPE_PP(zval) == IS_RESOURCE) { \ ! 410: ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp); \ ! 411: tmp_resource = 0; \ ! 412: } else { \ ! 413: if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) { \ ! 414: RETURN_FALSE; \ ! 415: } \ ! 416: tmp_resource = ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp); \ ! 417: } ! 418: ! 419: #define FREE_GMP_TEMP(tmp_resource) \ ! 420: if(tmp_resource) { \ ! 421: zend_list_delete(tmp_resource); \ ! 422: } ! 423: ! 424: ! 425: /* create a new initialized GMP number */ ! 426: #define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); } ! 427: #define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); } ! 428: ! 429: /* {{{ convert_to_gmp ! 430: * Convert zval to be gmp number */ ! 431: static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC) ! 432: { ! 433: int ret = 0; ! 434: int skip_lead = 0; ! 435: ! 436: *gmpnumber = emalloc(sizeof(mpz_t)); ! 437: ! 438: switch (Z_TYPE_PP(val)) { ! 439: case IS_LONG: ! 440: case IS_BOOL: ! 441: case IS_CONSTANT: ! 442: { ! 443: convert_to_long_ex(val); ! 444: mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val)); ! 445: } ! 446: break; ! 447: case IS_STRING: ! 448: { ! 449: char *numstr = Z_STRVAL_PP(val); ! 450: ! 451: if (Z_STRLEN_PP(val) > 2) { ! 452: if (numstr[0] == '0') { ! 453: if (numstr[1] == 'x' || numstr[1] == 'X') { ! 454: base = 16; ! 455: skip_lead = 1; ! 456: } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) { ! 457: base = 2; ! 458: skip_lead = 1; ! 459: } ! 460: } ! 461: } ! 462: ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base); ! 463: } ! 464: break; ! 465: default: ! 466: php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type"); ! 467: efree(*gmpnumber); ! 468: return FAILURE; ! 469: } ! 470: ! 471: if (ret) { ! 472: FREE_GMP_NUM(*gmpnumber); ! 473: return FAILURE; ! 474: } ! 475: ! 476: return SUCCESS; ! 477: } ! 478: /* }}} */ ! 479: ! 480: /* {{{ typedefs ! 481: */ ! 482: typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); ! 483: typedef int (*gmp_unary_opl_t)(mpz_srcptr); ! 484: ! 485: typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long); ! 486: ! 487: typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); ! 488: typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr); ! 489: ! 490: typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); ! 491: typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); ! 492: typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); ! 493: /* }}} */ ! 494: ! 495: #define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) ! 496: #define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) ! 497: ! 498: #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop) ! 499: #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL) ! 500: #define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) ! 501: ! 502: /* Unary operations */ ! 503: #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) ! 504: #define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) ! 505: #define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) ! 506: ! 507: /* {{{ gmp_zval_binary_ui_op_ex ! 508: Execute GMP binary operation. ! 509: May return GMP resource or long if operation allows this ! 510: */ ! 511: static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC) ! 512: { ! 513: mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; ! 514: unsigned long long_result = 0; ! 515: int use_ui = 0; ! 516: int arga_tmp = 0, argb_tmp = 0; ! 517: ! 518: FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp); ! 519: ! 520: if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { ! 521: use_ui = 1; ! 522: } else { ! 523: FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp); ! 524: } ! 525: ! 526: if(check_b_zero) { ! 527: int b_is_zero = 0; ! 528: if(use_ui) { ! 529: b_is_zero = (Z_LVAL_PP(b_arg) == 0); ! 530: } else { ! 531: b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); ! 532: } ! 533: ! 534: if(b_is_zero) { ! 535: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); ! 536: FREE_GMP_TEMP(arga_tmp); ! 537: FREE_GMP_TEMP(argb_tmp); ! 538: RETURN_FALSE; ! 539: } ! 540: } ! 541: ! 542: INIT_GMP_NUM(gmpnum_result); ! 543: ! 544: if (use_ui && gmp_ui_op) { ! 545: if (allow_ui_return) { ! 546: long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); ! 547: if (use_sign && mpz_sgn(*gmpnum_a) == -1) { ! 548: long_result = -long_result; ! 549: } ! 550: } else { ! 551: gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); ! 552: } ! 553: } else { ! 554: gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b); ! 555: } ! 556: ! 557: FREE_GMP_TEMP(arga_tmp); ! 558: FREE_GMP_TEMP(argb_tmp); ! 559: ! 560: if (use_ui && allow_ui_return) { ! 561: FREE_GMP_NUM(gmpnum_result); ! 562: RETURN_LONG((long)long_result); ! 563: } else { ! 564: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 565: } ! 566: } ! 567: /* }}} */ ! 568: ! 569: /* {{{ gmp_zval_binary_ui_op2_ex ! 570: Execute GMP binary operation which returns 2 values. ! 571: May return GMP resources or longs if operation allows this. ! 572: */ ! 573: static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return, int check_b_zero TSRMLS_DC) ! 574: { ! 575: mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2; ! 576: zval r; ! 577: int use_ui = 0; ! 578: unsigned long long_result = 0; ! 579: int arga_tmp = 0, argb_tmp = 0; ! 580: ! 581: FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp); ! 582: ! 583: if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { ! 584: /* use _ui function */ ! 585: use_ui = 1; ! 586: } else { ! 587: FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp); ! 588: } ! 589: ! 590: if(check_b_zero) { ! 591: int b_is_zero = 0; ! 592: if(use_ui) { ! 593: b_is_zero = (Z_LVAL_PP(b_arg) == 0); ! 594: } else { ! 595: b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); ! 596: } ! 597: ! 598: if(b_is_zero) { ! 599: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); ! 600: FREE_GMP_TEMP(arga_tmp); ! 601: FREE_GMP_TEMP(argb_tmp); ! 602: RETURN_FALSE; ! 603: } ! 604: } ! 605: ! 606: INIT_GMP_NUM(gmpnum_result1); ! 607: INIT_GMP_NUM(gmpnum_result2); ! 608: ! 609: if (use_ui && gmp_ui_op) { ! 610: if (allow_ui_return) { ! 611: long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); ! 612: } else { ! 613: gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); ! 614: } ! 615: } else { ! 616: gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b); ! 617: } ! 618: ! 619: FREE_GMP_TEMP(arga_tmp); ! 620: FREE_GMP_TEMP(argb_tmp); ! 621: ! 622: array_init(return_value); ! 623: ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); ! 624: add_index_resource(return_value, 0, Z_LVAL(r)); ! 625: if (use_ui && allow_ui_return) { ! 626: mpz_clear(*gmpnum_result2); ! 627: add_index_long(return_value, 1, long_result); ! 628: } else { ! 629: ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp); ! 630: add_index_resource(return_value, 1, Z_LVAL(r)); ! 631: } ! 632: } ! 633: /* }}} */ ! 634: ! 635: /* {{{ _gmp_binary_ui_op ! 636: */ ! 637: static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op) ! 638: { ! 639: zval **a_arg, **b_arg; ! 640: ! 641: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 642: return; ! 643: } ! 644: ! 645: gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op); ! 646: } ! 647: /* }}} */ ! 648: ! 649: /* Unary operations */ ! 650: ! 651: /* {{{ gmp_zval_unary_op ! 652: */ ! 653: static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) ! 654: { ! 655: mpz_t *gmpnum_a, *gmpnum_result; ! 656: int temp_a; ! 657: ! 658: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 659: ! 660: INIT_GMP_NUM(gmpnum_result); ! 661: gmp_op(*gmpnum_result, *gmpnum_a); ! 662: ! 663: FREE_GMP_TEMP(temp_a); ! 664: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 665: } ! 666: /* }}} */ ! 667: ! 668: /* {{{ gmp_zval_unary_ui_op ! 669: */ ! 670: static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op) ! 671: { ! 672: mpz_t *gmpnum_result; ! 673: ! 674: convert_to_long_ex(a_arg); ! 675: ! 676: INIT_GMP_NUM(gmpnum_result); ! 677: gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg)); ! 678: ! 679: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 680: } ! 681: /* }}} */ ! 682: ! 683: /* {{{ _gmp_unary_ui_op ! 684: Execute GMP unary operation. ! 685: */ ! 686: static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op) ! 687: { ! 688: zval **a_arg; ! 689: ! 690: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 691: return; ! 692: } ! 693: ! 694: gmp_zval_unary_ui_op(return_value, a_arg, gmp_op); ! 695: } ! 696: /* }}} */ ! 697: ! 698: /* {{{ _gmp_unary_op ! 699: */ ! 700: static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op) ! 701: { ! 702: zval **a_arg; ! 703: ! 704: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 705: return; ! 706: } ! 707: ! 708: gmp_zval_unary_op(return_value, a_arg, gmp_op TSRMLS_CC); ! 709: } ! 710: /* }}} */ ! 711: ! 712: /* {{{ _gmp_unary_opl ! 713: */ ! 714: static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op) ! 715: { ! 716: zval **a_arg; ! 717: mpz_t *gmpnum_a; ! 718: int temp_a; ! 719: ! 720: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 721: return; ! 722: } ! 723: ! 724: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 725: RETVAL_LONG(gmp_op(*gmpnum_a)); ! 726: FREE_GMP_TEMP(temp_a); ! 727: } ! 728: /* }}} */ ! 729: ! 730: /* {{{ _gmp_binary_opl ! 731: */ ! 732: static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op) ! 733: { ! 734: zval **a_arg, **b_arg; ! 735: mpz_t *gmpnum_a, *gmpnum_b; ! 736: int temp_a, temp_b; ! 737: ! 738: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 739: return; ! 740: } ! 741: ! 742: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 743: FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); ! 744: ! 745: RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b)); ! 746: ! 747: FREE_GMP_TEMP(temp_a); ! 748: FREE_GMP_TEMP(temp_b); ! 749: } ! 750: /* }}} */ ! 751: ! 752: /* {{{ proto resource gmp_init(mixed number [, int base]) ! 753: Initializes GMP number */ ! 754: ZEND_FUNCTION(gmp_init) ! 755: { ! 756: zval **number_arg; ! 757: mpz_t * gmpnumber; ! 758: long base=0; ! 759: ! 760: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &number_arg, &base) == FAILURE) { ! 761: return; ! 762: } ! 763: ! 764: if (base && (base < 2 || base > MAX_BASE)) { ! 765: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE); ! 766: RETURN_FALSE; ! 767: } ! 768: ! 769: if (convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) { ! 770: RETURN_FALSE; ! 771: } ! 772: ! 773: /* Write your own code here to handle argument number. */ ! 774: ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp); ! 775: } ! 776: /* }}} */ ! 777: ! 778: /* {{{ proto int gmp_intval(resource gmpnumber) ! 779: Gets signed long value of GMP number */ ! 780: ZEND_FUNCTION(gmp_intval) ! 781: { ! 782: zval **gmpnumber_arg; ! 783: mpz_t * gmpnum; ! 784: ! 785: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &gmpnumber_arg) == FAILURE){ ! 786: return; ! 787: } ! 788: ! 789: if (Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) { ! 790: ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp); ! 791: RETVAL_LONG(mpz_get_si(*gmpnum)); ! 792: } else { ! 793: convert_to_long_ex(gmpnumber_arg); ! 794: RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg)); ! 795: } ! 796: } ! 797: /* }}} */ ! 798: ! 799: /* {{{ proto string gmp_strval(resource gmpnumber [, int base]) ! 800: Gets string representation of GMP number */ ! 801: ZEND_FUNCTION(gmp_strval) ! 802: { ! 803: zval **gmpnumber_arg; ! 804: int num_len; ! 805: long base = 10; ! 806: mpz_t * gmpnum; ! 807: char *out_string; ! 808: int temp_a; ! 809: ! 810: if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base ) == FAILURE ) { ! 811: return; ! 812: } ! 813: ! 814: #if MAX_BASE == 62 ! 815: /* Although the maximum base in general in GMP >= 4.2 is 62, mpz_get_str() ! 816: * is explicitly limited to -36 when dealing with negative bases. */ ! 817: if ((base < 2 && base > -2) || base > MAX_BASE || base < -36) { ! 818: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d or -2 and -36)", base, MAX_BASE); ! 819: #else ! 820: if (base < 2 || base > MAX_BASE) { ! 821: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Bad base for conversion: %ld (should be between 2 and %d)", base, MAX_BASE); ! 822: #endif ! 823: RETURN_FALSE; ! 824: } ! 825: ! 826: FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a); ! 827: ! 828: num_len = mpz_sizeinbase(*gmpnum, abs(base)); ! 829: out_string = emalloc(num_len+2); ! 830: if (mpz_sgn(*gmpnum) < 0) { ! 831: num_len++; ! 832: } ! 833: mpz_get_str(out_string, base, *gmpnum); ! 834: ! 835: FREE_GMP_TEMP(temp_a); ! 836: ! 837: /* ! 838: From GMP documentation for mpz_sizeinbase(): ! 839: The returned value will be exact or 1 too big. If base is a power of ! 840: 2, the returned value will always be exact. ! 841: ! 842: So let's check to see if we already have a \0 byte... ! 843: */ ! 844: ! 845: if (out_string[num_len-1] == '\0') { ! 846: num_len--; ! 847: } else { ! 848: out_string[num_len] = '\0'; ! 849: } ! 850: RETVAL_STRINGL(out_string, num_len, 0); ! 851: } ! 852: /* }}} */ ! 853: ! 854: /* {{{ proto resource gmp_add(resource a, resource b) ! 855: Add a and b */ ! 856: ZEND_FUNCTION(gmp_add) ! 857: { ! 858: gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui); ! 859: } ! 860: /* }}} */ ! 861: ! 862: /* {{{ proto resource gmp_sub(resource a, resource b) ! 863: Subtract b from a */ ! 864: ZEND_FUNCTION(gmp_sub) ! 865: { ! 866: gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui); ! 867: } ! 868: /* }}} */ ! 869: ! 870: /* {{{ proto resource gmp_mul(resource a, resource b) ! 871: Multiply a and b */ ! 872: ZEND_FUNCTION(gmp_mul) ! 873: { ! 874: gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui); ! 875: } ! 876: /* }}} */ ! 877: ! 878: /* {{{ proto array gmp_div_qr(resource a, resource b [, int round]) ! 879: Divide a by b, returns quotient and reminder */ ! 880: ZEND_FUNCTION(gmp_div_qr) ! 881: { ! 882: zval **a_arg, **b_arg; ! 883: long round = GMP_ROUND_ZERO; ! 884: ! 885: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { ! 886: return; ! 887: } ! 888: ! 889: switch (round) { ! 890: case GMP_ROUND_ZERO: ! 891: gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 0, 1 TSRMLS_CC); ! 892: break; ! 893: case GMP_ROUND_PLUSINF: ! 894: gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 0, 1 TSRMLS_CC); ! 895: break; ! 896: case GMP_ROUND_MINUSINF: ! 897: gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 0, 1 TSRMLS_CC); ! 898: break; ! 899: } ! 900: ! 901: } ! 902: /* }}} */ ! 903: ! 904: /* {{{ proto resource gmp_div_r(resource a, resource b [, int round]) ! 905: Divide a by b, returns reminder only */ ! 906: ZEND_FUNCTION(gmp_div_r) ! 907: { ! 908: zval **a_arg, **b_arg; ! 909: long round = GMP_ROUND_ZERO; ! 910: ! 911: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { ! 912: return; ! 913: } ! 914: ! 915: switch (round) { ! 916: case GMP_ROUND_ZERO: ! 917: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1, 1, 1 TSRMLS_CC); ! 918: break; ! 919: case GMP_ROUND_PLUSINF: ! 920: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1, 1, 1 TSRMLS_CC); ! 921: break; ! 922: case GMP_ROUND_MINUSINF: ! 923: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1, 1, 1 TSRMLS_CC); ! 924: break; ! 925: } ! 926: } ! 927: /* }}} */ ! 928: ! 929: /* {{{ proto resource gmp_div_q(resource a, resource b [, int round]) ! 930: Divide a by b, returns quotient only */ ! 931: ZEND_FUNCTION(gmp_div_q) ! 932: { ! 933: zval **a_arg, **b_arg; ! 934: long round = GMP_ROUND_ZERO; ! 935: ! 936: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { ! 937: return; ! 938: } ! 939: ! 940: switch (round) { ! 941: case GMP_ROUND_ZERO: ! 942: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 0, 1, 1 TSRMLS_CC); ! 943: break; ! 944: case GMP_ROUND_PLUSINF: ! 945: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 0, 1, 1 TSRMLS_CC); ! 946: break; ! 947: case GMP_ROUND_MINUSINF: ! 948: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 0, 1, 1 TSRMLS_CC); ! 949: break; ! 950: } ! 951: ! 952: } ! 953: /* }}} */ ! 954: ! 955: /* {{{ proto resource gmp_mod(resource a, resource b) ! 956: Computes a modulo b */ ! 957: ZEND_FUNCTION(gmp_mod) ! 958: { ! 959: zval **a_arg, **b_arg; ! 960: ! 961: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 962: return; ! 963: } ! 964: ! 965: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui, 1, 1, 0 TSRMLS_CC); ! 966: } ! 967: /* }}} */ ! 968: ! 969: /* {{{ proto resource gmp_divexact(resource a, resource b) ! 970: Divide a by b using exact division algorithm */ ! 971: ZEND_FUNCTION(gmp_divexact) ! 972: { ! 973: zval **a_arg, **b_arg; ! 974: ! 975: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 976: return; ! 977: } ! 978: ! 979: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_divexact, NULL, 0, 1, 1 TSRMLS_CC); ! 980: } ! 981: /* }}} */ ! 982: ! 983: /* {{{ proto resource gmp_neg(resource a) ! 984: Negates a number */ ! 985: ZEND_FUNCTION(gmp_neg) ! 986: { ! 987: gmp_unary_op(mpz_neg); ! 988: } ! 989: /* }}} */ ! 990: ! 991: /* {{{ proto resource gmp_abs(resource a) ! 992: Calculates absolute value */ ! 993: ZEND_FUNCTION(gmp_abs) ! 994: { ! 995: gmp_unary_op(mpz_abs); ! 996: } ! 997: /* }}} */ ! 998: ! 999: /* {{{ proto resource gmp_fact(int a) ! 1000: Calculates factorial function */ ! 1001: ZEND_FUNCTION(gmp_fact) ! 1002: { ! 1003: zval **a_arg; ! 1004: mpz_t *gmpnum_tmp; ! 1005: int temp_a; ! 1006: ! 1007: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 1008: return; ! 1009: } ! 1010: ! 1011: if (Z_TYPE_PP(a_arg) == IS_RESOURCE) { ! 1012: FETCH_GMP_ZVAL(gmpnum_tmp, a_arg, temp_a); /* no need to free this since it's IS_RESOURCE */ ! 1013: if (mpz_sgn(*gmpnum_tmp) < 0) { ! 1014: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); ! 1015: RETURN_FALSE; ! 1016: } ! 1017: } else { ! 1018: convert_to_long_ex(a_arg); ! 1019: if (Z_LVAL_PP(a_arg) < 0) { ! 1020: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); ! 1021: RETURN_FALSE; ! 1022: } ! 1023: } ! 1024: ! 1025: gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui); ! 1026: } ! 1027: /* }}} */ ! 1028: ! 1029: /* {{{ proto resource gmp_pow(resource base, int exp) ! 1030: Raise base to power exp */ ! 1031: ZEND_FUNCTION(gmp_pow) ! 1032: { ! 1033: zval **base_arg; ! 1034: mpz_t *gmpnum_result, *gmpnum_base; ! 1035: int use_ui = 0; ! 1036: int temp_base; ! 1037: long exp; ! 1038: ! 1039: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) { ! 1040: return; ! 1041: } ! 1042: ! 1043: if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) { ! 1044: use_ui = 1; ! 1045: } else { ! 1046: FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); ! 1047: } ! 1048: ! 1049: if (exp < 0) { ! 1050: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported"); ! 1051: RETURN_FALSE; ! 1052: } ! 1053: ! 1054: INIT_GMP_NUM(gmpnum_result); ! 1055: if (use_ui) { ! 1056: mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp); ! 1057: } else { ! 1058: mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp); ! 1059: FREE_GMP_TEMP(temp_base); ! 1060: } ! 1061: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 1062: } ! 1063: /* }}} */ ! 1064: ! 1065: /* {{{ proto resource gmp_powm(resource base, resource exp, resource mod) ! 1066: Raise base to power exp and take result modulo mod */ ! 1067: ZEND_FUNCTION(gmp_powm) ! 1068: { ! 1069: zval **base_arg, **exp_arg, **mod_arg; ! 1070: mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result; ! 1071: int use_ui = 0; ! 1072: int temp_base, temp_exp, temp_mod; ! 1073: ! 1074: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){ ! 1075: return; ! 1076: } ! 1077: ! 1078: FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); ! 1079: ! 1080: if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) { ! 1081: use_ui = 1; ! 1082: } else { ! 1083: FETCH_GMP_ZVAL(gmpnum_exp, exp_arg, temp_exp); ! 1084: if (mpz_sgn(*gmpnum_exp) < 0) { ! 1085: php_error_docref(NULL TSRMLS_CC, E_WARNING,"Second parameter cannot be less than 0"); ! 1086: RETURN_FALSE; ! 1087: } ! 1088: } ! 1089: FETCH_GMP_ZVAL(gmpnum_mod, mod_arg, temp_mod); ! 1090: ! 1091: if (!mpz_cmp_ui(*gmpnum_mod, 0)) { ! 1092: FREE_GMP_TEMP(temp_base); ! 1093: if (use_ui) { ! 1094: FREE_GMP_TEMP(temp_exp); ! 1095: } ! 1096: FREE_GMP_TEMP(temp_mod); ! 1097: RETURN_FALSE; ! 1098: } ! 1099: ! 1100: INIT_GMP_NUM(gmpnum_result); ! 1101: if (use_ui) { ! 1102: mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod); ! 1103: } else { ! 1104: mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod); ! 1105: FREE_GMP_TEMP(temp_exp); ! 1106: } ! 1107: ! 1108: FREE_GMP_TEMP(temp_base); ! 1109: FREE_GMP_TEMP(temp_mod); ! 1110: ! 1111: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 1112: ! 1113: } ! 1114: /* }}} */ ! 1115: ! 1116: /* {{{ proto resource gmp_sqrt(resource a) ! 1117: Takes integer part of square root of a */ ! 1118: ZEND_FUNCTION(gmp_sqrt) ! 1119: { ! 1120: zval **a_arg; ! 1121: mpz_t *gmpnum_a, *gmpnum_result; ! 1122: int temp_a; ! 1123: ! 1124: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 1125: return; ! 1126: } ! 1127: ! 1128: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1129: ! 1130: if (mpz_sgn(*gmpnum_a) < 0) { ! 1131: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); ! 1132: FREE_GMP_TEMP(temp_a); ! 1133: RETURN_FALSE; ! 1134: } ! 1135: ! 1136: INIT_GMP_NUM(gmpnum_result); ! 1137: mpz_sqrt(*gmpnum_result, *gmpnum_a); ! 1138: FREE_GMP_TEMP(temp_a); ! 1139: ! 1140: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 1141: } ! 1142: /* }}} */ ! 1143: ! 1144: /* {{{ proto array gmp_sqrtrem(resource a) ! 1145: Square root with remainder */ ! 1146: ZEND_FUNCTION(gmp_sqrtrem) ! 1147: { ! 1148: zval **a_arg; ! 1149: mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2; ! 1150: zval r; ! 1151: int temp_a; ! 1152: ! 1153: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 1154: return; ! 1155: } ! 1156: ! 1157: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1158: ! 1159: if (mpz_sgn(*gmpnum_a) < 0) { ! 1160: php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0"); ! 1161: RETURN_FALSE; ! 1162: } ! 1163: ! 1164: INIT_GMP_NUM(gmpnum_result1); ! 1165: INIT_GMP_NUM(gmpnum_result2); ! 1166: ! 1167: mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a); ! 1168: FREE_GMP_TEMP(temp_a); ! 1169: ! 1170: array_init(return_value); ! 1171: ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); ! 1172: add_index_resource(return_value, 0, Z_LVAL(r)); ! 1173: ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp); ! 1174: add_index_resource(return_value, 1, Z_LVAL(r)); ! 1175: } ! 1176: /* }}} */ ! 1177: ! 1178: /* {{{ proto bool gmp_perfect_square(resource a) ! 1179: Checks if a is an exact square */ ! 1180: ZEND_FUNCTION(gmp_perfect_square) ! 1181: { ! 1182: zval **a_arg; ! 1183: mpz_t *gmpnum_a; ! 1184: int temp_a; ! 1185: ! 1186: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 1187: return; ! 1188: } ! 1189: ! 1190: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1191: ! 1192: RETVAL_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0)); ! 1193: FREE_GMP_TEMP(temp_a); ! 1194: } ! 1195: /* }}} */ ! 1196: ! 1197: /* {{{ proto int gmp_prob_prime(resource a[, int reps]) ! 1198: Checks if a is "probably prime" */ ! 1199: ZEND_FUNCTION(gmp_prob_prime) ! 1200: { ! 1201: zval **gmpnumber_arg; ! 1202: mpz_t *gmpnum_a; ! 1203: long reps = 10; ! 1204: int temp_a; ! 1205: ! 1206: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) { ! 1207: return; ! 1208: } ! 1209: ! 1210: FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a); ! 1211: ! 1212: RETVAL_LONG(mpz_probab_prime_p(*gmpnum_a, reps)); ! 1213: FREE_GMP_TEMP(temp_a); ! 1214: } ! 1215: /* }}} */ ! 1216: ! 1217: /* {{{ proto resource gmp_gcd(resource a, resource b) ! 1218: Computes greatest common denominator (gcd) of a and b */ ! 1219: ZEND_FUNCTION(gmp_gcd) ! 1220: { ! 1221: zval **a_arg, **b_arg; ! 1222: ! 1223: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 1224: return; ! 1225: } ! 1226: ! 1227: gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui, 0, 0, 1 TSRMLS_CC); ! 1228: } ! 1229: /* }}} */ ! 1230: ! 1231: /* {{{ proto array gmp_gcdext(resource a, resource b) ! 1232: Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */ ! 1233: ZEND_FUNCTION(gmp_gcdext) ! 1234: { ! 1235: zval **a_arg, **b_arg; ! 1236: mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g; ! 1237: zval r; ! 1238: int temp_a, temp_b; ! 1239: ! 1240: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 1241: return; ! 1242: } ! 1243: ! 1244: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1245: FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); ! 1246: ! 1247: INIT_GMP_NUM(gmpnum_g); ! 1248: INIT_GMP_NUM(gmpnum_s); ! 1249: INIT_GMP_NUM(gmpnum_t); ! 1250: ! 1251: mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b); ! 1252: FREE_GMP_TEMP(temp_a); ! 1253: FREE_GMP_TEMP(temp_b); ! 1254: ! 1255: array_init(return_value); ! 1256: ! 1257: ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp); ! 1258: add_assoc_resource(return_value, "g", Z_LVAL(r)); ! 1259: ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp); ! 1260: add_assoc_resource(return_value, "s", Z_LVAL(r)); ! 1261: ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp); ! 1262: add_assoc_resource(return_value, "t", Z_LVAL(r)); ! 1263: } ! 1264: /* }}} */ ! 1265: ! 1266: /* {{{ proto resource gmp_invert(resource a, resource b) ! 1267: Computes the inverse of a modulo b */ ! 1268: ZEND_FUNCTION(gmp_invert) ! 1269: { ! 1270: zval **a_arg, **b_arg; ! 1271: mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; ! 1272: int temp_a, temp_b; ! 1273: int res; ! 1274: ! 1275: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 1276: return; ! 1277: } ! 1278: ! 1279: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1280: FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); ! 1281: ! 1282: INIT_GMP_NUM(gmpnum_result); ! 1283: res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b); ! 1284: FREE_GMP_TEMP(temp_a); ! 1285: FREE_GMP_TEMP(temp_b); ! 1286: if (res) { ! 1287: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 1288: } else { ! 1289: FREE_GMP_NUM(gmpnum_result); ! 1290: RETURN_FALSE; ! 1291: } ! 1292: } ! 1293: /* }}} */ ! 1294: ! 1295: /* {{{ proto int gmp_jacobi(resource a, resource b) ! 1296: Computes Jacobi symbol */ ! 1297: ZEND_FUNCTION(gmp_jacobi) ! 1298: { ! 1299: gmp_binary_opl(mpz_jacobi); ! 1300: } ! 1301: /* }}} */ ! 1302: ! 1303: /* {{{ proto int gmp_legendre(resource a, resource b) ! 1304: Computes Legendre symbol */ ! 1305: ZEND_FUNCTION(gmp_legendre) ! 1306: { ! 1307: gmp_binary_opl(mpz_legendre); ! 1308: } ! 1309: /* }}} */ ! 1310: ! 1311: /* {{{ proto int gmp_cmp(resource a, resource b) ! 1312: Compares two numbers */ ! 1313: ZEND_FUNCTION(gmp_cmp) ! 1314: { ! 1315: zval **a_arg, **b_arg; ! 1316: mpz_t *gmpnum_a, *gmpnum_b; ! 1317: int use_si = 0, res; ! 1318: int temp_a, temp_b; ! 1319: ! 1320: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 1321: return; ! 1322: } ! 1323: ! 1324: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1325: ! 1326: if (Z_TYPE_PP(b_arg) == IS_LONG) { ! 1327: use_si = 1; ! 1328: } else { ! 1329: FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); ! 1330: } ! 1331: ! 1332: if (use_si) { ! 1333: res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg)); ! 1334: } else { ! 1335: res = mpz_cmp(*gmpnum_a, *gmpnum_b); ! 1336: } ! 1337: FREE_GMP_TEMP(temp_a); ! 1338: ! 1339: RETURN_LONG(res); ! 1340: } ! 1341: /* }}} */ ! 1342: ! 1343: /* {{{ proto int gmp_sign(resource a) ! 1344: Gets the sign of the number */ ! 1345: ZEND_FUNCTION(gmp_sign) ! 1346: { ! 1347: zval **a_arg; ! 1348: mpz_t *gmpnum_a; ! 1349: int temp_a; ! 1350: ! 1351: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 1352: return; ! 1353: } ! 1354: ! 1355: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1356: ! 1357: RETVAL_LONG(mpz_sgn(*gmpnum_a)); ! 1358: FREE_GMP_TEMP(temp_a); ! 1359: } ! 1360: /* }}} */ ! 1361: ! 1362: /* {{{ proto resource gmp_random([int limiter]) ! 1363: Gets random number */ ! 1364: ZEND_FUNCTION(gmp_random) ! 1365: { ! 1366: long limiter = 20; ! 1367: mpz_t *gmpnum_result; ! 1368: ! 1369: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) { ! 1370: return; ! 1371: } ! 1372: ! 1373: INIT_GMP_NUM(gmpnum_result); ! 1374: ! 1375: if (!GMPG(rand_initialized)) { ! 1376: /* Initialize */ ! 1377: gmp_randinit_lc_2exp_size(GMPG(rand_state), 32L); ! 1378: ! 1379: /* Seed */ ! 1380: gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED()); ! 1381: ! 1382: GMPG(rand_initialized) = 1; ! 1383: } ! 1384: #ifdef GMP_LIMB_BITS ! 1385: mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS); ! 1386: #else ! 1387: mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB); ! 1388: #endif ! 1389: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 1390: } ! 1391: /* }}} */ ! 1392: ! 1393: /* {{{ proto resource gmp_and(resource a, resource b) ! 1394: Calculates logical AND of a and b */ ! 1395: ZEND_FUNCTION(gmp_and) ! 1396: { ! 1397: gmp_binary_op(mpz_and); ! 1398: } ! 1399: /* }}} */ ! 1400: ! 1401: /* {{{ proto resource gmp_or(resource a, resource b) ! 1402: Calculates logical OR of a and b */ ! 1403: ZEND_FUNCTION(gmp_or) ! 1404: { ! 1405: gmp_binary_op(mpz_ior); ! 1406: } ! 1407: /* }}} */ ! 1408: ! 1409: /* {{{ proto resource gmp_com(resource a) ! 1410: Calculates one's complement of a */ ! 1411: ZEND_FUNCTION(gmp_com) ! 1412: { ! 1413: gmp_unary_op(mpz_com); ! 1414: } ! 1415: /* }}} */ ! 1416: ! 1417: /* {{{ proto resource gmp_nextprime(resource a) ! 1418: Finds next prime of a */ ! 1419: ZEND_FUNCTION(gmp_nextprime) ! 1420: { ! 1421: gmp_unary_op(mpz_nextprime); ! 1422: } ! 1423: /* }}} */ ! 1424: ! 1425: /* {{{ proto resource gmp_xor(resource a, resource b) ! 1426: Calculates logical exclusive OR of a and b */ ! 1427: ZEND_FUNCTION(gmp_xor) ! 1428: { ! 1429: /* use formula: a^b = (a|b)&^(a&b) */ ! 1430: zval **a_arg, **b_arg; ! 1431: mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t; ! 1432: int temp_a, temp_b; ! 1433: ! 1434: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 1435: return; ! 1436: } ! 1437: ! 1438: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1439: FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); ! 1440: ! 1441: INIT_GMP_NUM(gmpnum_result); ! 1442: INIT_GMP_NUM(gmpnum_t); ! 1443: ! 1444: mpz_and(*gmpnum_t, *gmpnum_a, *gmpnum_b); ! 1445: mpz_com(*gmpnum_t, *gmpnum_t); ! 1446: ! 1447: mpz_ior(*gmpnum_result, *gmpnum_a, *gmpnum_b); ! 1448: mpz_and(*gmpnum_result, *gmpnum_result, *gmpnum_t); ! 1449: ! 1450: FREE_GMP_NUM(gmpnum_t); ! 1451: ! 1452: FREE_GMP_TEMP(temp_a); ! 1453: FREE_GMP_TEMP(temp_b); ! 1454: ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); ! 1455: } ! 1456: /* }}} */ ! 1457: ! 1458: /* {{{ proto void gmp_setbit(resource &a, int index[, bool set_clear]) ! 1459: Sets or clear bit in a */ ! 1460: ZEND_FUNCTION(gmp_setbit) ! 1461: { ! 1462: zval **a_arg; ! 1463: long index; ! 1464: zend_bool set = 1; ! 1465: mpz_t *gmpnum_a; ! 1466: ! 1467: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|b", &a_arg, &index, &set) == FAILURE) { ! 1468: return; ! 1469: } ! 1470: ! 1471: ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); ! 1472: ! 1473: if (index < 0) { ! 1474: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); ! 1475: return; ! 1476: } ! 1477: ! 1478: if (set) { ! 1479: mpz_setbit(*gmpnum_a, index); ! 1480: } else { ! 1481: mpz_clrbit(*gmpnum_a, index); ! 1482: } ! 1483: } ! 1484: /* }}} */ ! 1485: ! 1486: /* {{{ proto void gmp_clrbit(resource &a, int index) ! 1487: Clears bit in a */ ! 1488: ZEND_FUNCTION(gmp_clrbit) ! 1489: { ! 1490: zval **a_arg; ! 1491: long index; ! 1492: mpz_t *gmpnum_a; ! 1493: ! 1494: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){ ! 1495: return; ! 1496: } ! 1497: ! 1498: ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); ! 1499: ! 1500: if (index < 0) { ! 1501: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); ! 1502: return; ! 1503: } ! 1504: ! 1505: mpz_clrbit(*gmpnum_a, index); ! 1506: } ! 1507: /* }}} */ ! 1508: ! 1509: /* {{{ proto bool gmp_testbit(resource a, int index) ! 1510: Tests if bit is set in a */ ! 1511: ZEND_FUNCTION(gmp_testbit) ! 1512: { ! 1513: zval **a_arg; ! 1514: long index; ! 1515: mpz_t *gmpnum_a; ! 1516: ! 1517: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){ ! 1518: return; ! 1519: } ! 1520: ! 1521: ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); ! 1522: ! 1523: if (index < 0) { ! 1524: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); ! 1525: RETURN_FALSE; ! 1526: } ! 1527: ! 1528: if (mpz_tstbit(*gmpnum_a, index)) { ! 1529: RETURN_TRUE; ! 1530: } ! 1531: RETURN_FALSE; ! 1532: } ! 1533: /* }}} */ ! 1534: ! 1535: /* {{{ proto int gmp_popcount(resource a) ! 1536: Calculates the population count of a */ ! 1537: ZEND_FUNCTION(gmp_popcount) ! 1538: { ! 1539: zval **a_arg; ! 1540: mpz_t *gmpnum_a; ! 1541: int temp_a; ! 1542: ! 1543: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ ! 1544: return; ! 1545: } ! 1546: ! 1547: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1548: ! 1549: RETVAL_LONG(mpz_popcount(*gmpnum_a)); ! 1550: FREE_GMP_TEMP(temp_a); ! 1551: } ! 1552: /* }}} */ ! 1553: ! 1554: /* {{{ proto int gmp_hamdist(resource a, resource b) ! 1555: Calculates hamming distance between a and b */ ! 1556: ZEND_FUNCTION(gmp_hamdist) ! 1557: { ! 1558: zval **a_arg, **b_arg; ! 1559: mpz_t *gmpnum_a, *gmpnum_b; ! 1560: int temp_a, temp_b; ! 1561: ! 1562: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ ! 1563: return; ! 1564: } ! 1565: ! 1566: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1567: FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); ! 1568: ! 1569: RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b)); ! 1570: FREE_GMP_TEMP(temp_a); ! 1571: FREE_GMP_TEMP(temp_b); ! 1572: } ! 1573: /* }}} */ ! 1574: ! 1575: /* {{{ proto int gmp_scan0(resource a, int start) ! 1576: Finds first zero bit */ ! 1577: ZEND_FUNCTION(gmp_scan0) ! 1578: { ! 1579: zval **a_arg; ! 1580: mpz_t *gmpnum_a; ! 1581: int temp_a; ! 1582: long start; ! 1583: ! 1584: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ ! 1585: return; ! 1586: } ! 1587: ! 1588: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1589: ! 1590: if (start < 0) { ! 1591: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero"); ! 1592: RETURN_FALSE; ! 1593: } ! 1594: ! 1595: RETVAL_LONG(mpz_scan0(*gmpnum_a, start)); ! 1596: FREE_GMP_TEMP(temp_a); ! 1597: } ! 1598: /* }}} */ ! 1599: ! 1600: /* {{{ proto int gmp_scan1(resource a, int start) ! 1601: Finds first non-zero bit */ ! 1602: ZEND_FUNCTION(gmp_scan1) ! 1603: { ! 1604: zval **a_arg; ! 1605: mpz_t *gmpnum_a; ! 1606: int temp_a; ! 1607: long start; ! 1608: ! 1609: if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ ! 1610: return; ! 1611: } ! 1612: ! 1613: FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); ! 1614: if (start < 0) { ! 1615: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero"); ! 1616: RETURN_FALSE; ! 1617: } ! 1618: ! 1619: RETVAL_LONG(mpz_scan1(*gmpnum_a, start)); ! 1620: FREE_GMP_TEMP(temp_a); ! 1621: } ! 1622: /* }}} */ ! 1623: ! 1624: /* {{{ _php_gmpnum_free ! 1625: */ ! 1626: static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) ! 1627: { ! 1628: mpz_t *gmpnum = (mpz_t *)rsrc->ptr; ! 1629: ! 1630: FREE_GMP_NUM(gmpnum); ! 1631: } ! 1632: /* }}} */ ! 1633: ! 1634: #endif /* HAVE_GMP */ ! 1635: ! 1636: /* ! 1637: * Local variables: ! 1638: * tab-width: 4 ! 1639: * c-basic-offset: 4 ! 1640: * End: ! 1641: * vim600: noet sw=4 ts=4 fdm=marker ! 1642: * vim<600: noet sw=4 ts=4 ! 1643: */