Annotation of embedaddon/php/ext/gmp/gmp.c, revision 1.1.1.3
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
1.1.1.3 ! misho 5: | Copyright (c) 1997-2013 The PHP Group |
1.1 misho 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: */
1.1.1.2 misho 670: static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC)
1.1 misho 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:
1.1.1.2 misho 694: gmp_zval_unary_ui_op(return_value, a_arg, gmp_op TSRMLS_CC);
1.1 misho 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;
1.1.1.2 misho 963: }
1.1 misho 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:
1.1.1.2 misho 1025: gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC);
1.1 misho 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: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>