gmp.c 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Author: Stanislav Malyshev <stas@php.net> |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifdef HAVE_CONFIG_H
  17. #include "config.h"
  18. #endif
  19. #include "php.h"
  20. #include "php_ini.h"
  21. #include "php_gmp.h"
  22. #include "php_gmp_int.h"
  23. #include "ext/standard/info.h"
  24. #include "ext/standard/php_var.h"
  25. #include "zend_smart_str_public.h"
  26. #include "zend_exceptions.h"
  27. #include <gmp.h>
  28. #include "gmp_arginfo.h"
  29. /* Needed for gmp_random() */
  30. #include "ext/standard/php_rand.h"
  31. #include "ext/standard/php_lcg.h"
  32. ZEND_DECLARE_MODULE_GLOBALS(gmp)
  33. static ZEND_GINIT_FUNCTION(gmp);
  34. /* {{{ gmp_module_entry */
  35. zend_module_entry gmp_module_entry = {
  36. STANDARD_MODULE_HEADER,
  37. "gmp",
  38. ext_functions,
  39. ZEND_MODULE_STARTUP_N(gmp),
  40. NULL,
  41. NULL,
  42. ZEND_MODULE_DEACTIVATE_N(gmp),
  43. ZEND_MODULE_INFO_N(gmp),
  44. PHP_GMP_VERSION,
  45. ZEND_MODULE_GLOBALS(gmp),
  46. ZEND_GINIT(gmp),
  47. NULL,
  48. NULL,
  49. STANDARD_MODULE_PROPERTIES_EX
  50. };
  51. /* }}} */
  52. #ifdef COMPILE_DL_GMP
  53. #ifdef ZTS
  54. ZEND_TSRMLS_CACHE_DEFINE()
  55. #endif
  56. ZEND_GET_MODULE(gmp)
  57. #endif
  58. static zend_class_entry *gmp_ce;
  59. static zend_object_handlers gmp_object_handlers;
  60. PHP_GMP_API zend_class_entry *php_gmp_class_entry(void) {
  61. return gmp_ce;
  62. }
  63. typedef struct _gmp_temp {
  64. mpz_t num;
  65. bool is_used;
  66. } gmp_temp_t;
  67. #define GMP_ROUND_ZERO 0
  68. #define GMP_ROUND_PLUSINF 1
  69. #define GMP_ROUND_MINUSINF 2
  70. #define GMP_MSW_FIRST (1 << 0)
  71. #define GMP_LSW_FIRST (1 << 1)
  72. #define GMP_LITTLE_ENDIAN (1 << 2)
  73. #define GMP_BIG_ENDIAN (1 << 3)
  74. #define GMP_NATIVE_ENDIAN (1 << 4)
  75. #define GMP_MAX_BASE 62
  76. #define GMP_51_OR_NEWER \
  77. ((__GNU_MP_VERSION >= 6) || (__GNU_MP_VERSION >= 5 && __GNU_MP_VERSION_MINOR >= 1))
  78. #define IS_GMP(zval) \
  79. (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce))
  80. #define GET_GMP_OBJECT_FROM_OBJ(obj) \
  81. php_gmp_object_from_zend_object(obj)
  82. #define GET_GMP_OBJECT_FROM_ZVAL(zv) \
  83. GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zv))
  84. #define GET_GMP_FROM_ZVAL(zval) \
  85. GET_GMP_OBJECT_FROM_OBJ(Z_OBJ_P(zval))->num
  86. /* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number
  87. * (mpz_ptr) from a zval. If the zval is not a GMP instance, then we
  88. * try to convert the value to a temporary gmp number using convert_to_gmp.
  89. * This temporary number is stored in the temp argument, which is of type
  90. * gmp_temp_t. This temporary value needs to be freed lateron using the
  91. * FREE_GMP_TEMP macro.
  92. *
  93. * If the conversion to a gmp number fails, the macros RETURN_THROWS() due to TypeError.
  94. * The _DEP / _DEP_DEP variants additionally free the temporary values
  95. * passed in the last / last two arguments.
  96. *
  97. * If one zval can sometimes be fetched as a long you have to set the
  98. * is_used member of the corresponding gmp_temp_t value to 0, otherwise
  99. * the FREE_GMP_TEMP and *_DEP macros will not work properly.
  100. *
  101. * The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code
  102. * as I couldn't find a way to combine them.
  103. */
  104. #define FREE_GMP_TEMP(temp) \
  105. if (temp.is_used) { \
  106. mpz_clear(temp.num); \
  107. }
  108. #define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2, arg_pos) \
  109. if (IS_GMP(zval)) { \
  110. gmpnumber = GET_GMP_FROM_ZVAL(zval); \
  111. temp.is_used = 0; \
  112. } else { \
  113. mpz_init(temp.num); \
  114. if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \
  115. mpz_clear(temp.num); \
  116. FREE_GMP_TEMP(dep1); \
  117. FREE_GMP_TEMP(dep2); \
  118. RETURN_THROWS(); \
  119. } \
  120. temp.is_used = 1; \
  121. gmpnumber = temp.num; \
  122. }
  123. #define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep, arg_pos) \
  124. if (IS_GMP(zval)) { \
  125. gmpnumber = GET_GMP_FROM_ZVAL(zval); \
  126. temp.is_used = 0; \
  127. } else { \
  128. mpz_init(temp.num); \
  129. if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \
  130. mpz_clear(temp.num); \
  131. FREE_GMP_TEMP(dep); \
  132. RETURN_THROWS(); \
  133. } \
  134. temp.is_used = 1; \
  135. gmpnumber = temp.num; \
  136. }
  137. #define FETCH_GMP_ZVAL(gmpnumber, zval, temp, arg_pos) \
  138. if (IS_GMP(zval)) { \
  139. gmpnumber = GET_GMP_FROM_ZVAL(zval); \
  140. temp.is_used = 0; \
  141. } else { \
  142. mpz_init(temp.num); \
  143. if (convert_to_gmp(temp.num, zval, 0, arg_pos) == FAILURE) { \
  144. mpz_clear(temp.num); \
  145. RETURN_THROWS(); \
  146. } \
  147. temp.is_used = 1; \
  148. gmpnumber = temp.num; \
  149. }
  150. #define INIT_GMP_RETVAL(gmpnumber) \
  151. gmp_create(return_value, &gmpnumber)
  152. static void gmp_strval(zval *result, mpz_t gmpnum, int base);
  153. static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos);
  154. static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator);
  155. /*
  156. * The gmp_*_op functions provide an implementation for several common types
  157. * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually
  158. * passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already
  159. * include parameter parsing.
  160. */
  161. typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr);
  162. typedef mp_bitcnt_t (*gmp_unary_opl_t)(mpz_srcptr);
  163. typedef void (*gmp_unary_ui_op_t)(mpz_ptr, gmp_ulong);
  164. typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr);
  165. typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, gmp_ulong);
  166. typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr);
  167. typedef gmp_ulong (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, gmp_ulong);
  168. static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator);
  169. static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero);
  170. static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op);
  171. static void gmp_mpz_tdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  172. mpz_tdiv_q_ui(a, b, c);
  173. }
  174. static void gmp_mpz_tdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  175. mpz_tdiv_r_ui(a, b, c);
  176. }
  177. static void gmp_mpz_fdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  178. mpz_fdiv_q_ui(a, b, c);
  179. }
  180. static void gmp_mpz_fdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  181. mpz_fdiv_r_ui(a, b, c);
  182. }
  183. static void gmp_mpz_cdiv_r_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  184. mpz_cdiv_r_ui(a, b, c);
  185. }
  186. static void gmp_mpz_cdiv_q_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  187. mpz_cdiv_q_ui(a, b, c);
  188. }
  189. static void gmp_mpz_mod_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  190. mpz_mod_ui(a, b, c);
  191. }
  192. static void gmp_mpz_gcd_ui(mpz_ptr a, mpz_srcptr b, gmp_ulong c) {
  193. mpz_gcd_ui(a, b, c);
  194. }
  195. /* Binary operations */
  196. #define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0)
  197. #define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0)
  198. #define gmp_binary_ui_op_no_zero(op, uop) \
  199. _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1)
  200. /* Unary operations */
  201. #define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
  202. #define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op)
  203. static void gmp_free_object_storage(zend_object *obj) /* {{{ */
  204. {
  205. gmp_object *intern = GET_GMP_OBJECT_FROM_OBJ(obj);
  206. mpz_clear(intern->num);
  207. zend_object_std_dtor(&intern->std);
  208. }
  209. /* }}} */
  210. static inline zend_object *gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target) /* {{{ */
  211. {
  212. gmp_object *intern = emalloc(sizeof(gmp_object) + zend_object_properties_size(ce));
  213. zend_object_std_init(&intern->std, ce);
  214. object_properties_init(&intern->std, ce);
  215. mpz_init(intern->num);
  216. *gmpnum_target = intern->num;
  217. intern->std.handlers = &gmp_object_handlers;
  218. return &intern->std;
  219. }
  220. /* }}} */
  221. static zend_object *gmp_create_object(zend_class_entry *ce) /* {{{ */
  222. {
  223. mpz_ptr gmpnum_dummy;
  224. return gmp_create_object_ex(ce, &gmpnum_dummy);
  225. }
  226. /* }}} */
  227. static inline void gmp_create(zval *target, mpz_ptr *gmpnum_target) /* {{{ */
  228. {
  229. ZVAL_OBJ(target, gmp_create_object_ex(gmp_ce, gmpnum_target));
  230. }
  231. /* }}} */
  232. static int gmp_cast_object(zend_object *readobj, zval *writeobj, int type) /* {{{ */
  233. {
  234. mpz_ptr gmpnum;
  235. switch (type) {
  236. case IS_STRING:
  237. gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
  238. gmp_strval(writeobj, gmpnum, 10);
  239. return SUCCESS;
  240. case IS_LONG:
  241. gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
  242. ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
  243. return SUCCESS;
  244. case IS_DOUBLE:
  245. gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
  246. ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
  247. return SUCCESS;
  248. case _IS_NUMBER:
  249. gmpnum = GET_GMP_OBJECT_FROM_OBJ(readobj)->num;
  250. if (mpz_fits_slong_p(gmpnum)) {
  251. ZVAL_LONG(writeobj, mpz_get_si(gmpnum));
  252. } else {
  253. ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum));
  254. }
  255. return SUCCESS;
  256. default:
  257. return FAILURE;
  258. }
  259. }
  260. /* }}} */
  261. static HashTable *gmp_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
  262. {
  263. HashTable *ht, *props = zend_std_get_properties(obj);
  264. mpz_ptr gmpnum = GET_GMP_OBJECT_FROM_OBJ(obj)->num;
  265. zval zv;
  266. *is_temp = 1;
  267. ht = zend_array_dup(props);
  268. gmp_strval(&zv, gmpnum, 10);
  269. zend_hash_str_update(ht, "num", sizeof("num")-1, &zv);
  270. return ht;
  271. }
  272. /* }}} */
  273. static zend_object *gmp_clone_obj(zend_object *obj) /* {{{ */
  274. {
  275. gmp_object *old_object = GET_GMP_OBJECT_FROM_OBJ(obj);
  276. gmp_object *new_object = GET_GMP_OBJECT_FROM_OBJ(gmp_create_object(obj->ce));
  277. zend_objects_clone_members( &new_object->std, &old_object->std);
  278. mpz_set(new_object->num, old_object->num);
  279. return &new_object->std;
  280. }
  281. /* }}} */
  282. static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2, zend_uchar opcode) {
  283. zend_long shift = zval_get_long(op2);
  284. if (shift < 0) {
  285. zend_throw_error(
  286. zend_ce_value_error, "%s must be greater than or equal to 0",
  287. opcode == ZEND_POW ? "Exponent" : "Shift"
  288. );
  289. ZVAL_UNDEF(return_value);
  290. return;
  291. } else {
  292. mpz_ptr gmpnum_op, gmpnum_result;
  293. gmp_temp_t temp;
  294. FETCH_GMP_ZVAL(gmpnum_op, op1, temp, 1);
  295. INIT_GMP_RETVAL(gmpnum_result);
  296. op(gmpnum_result, gmpnum_op, (gmp_ulong) shift);
  297. FREE_GMP_TEMP(temp);
  298. }
  299. }
  300. #define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \
  301. gmp_zval_binary_ui_op( \
  302. result, op1, op2, op, uop, check_b_zero, /* is_operator */ true); \
  303. if (UNEXPECTED(EG(exception))) { return FAILURE; } \
  304. return SUCCESS;
  305. #define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0)
  306. #define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0)
  307. #define DO_UNARY_OP(op) \
  308. gmp_zval_unary_op(result, op1, op); \
  309. if (UNEXPECTED(EG(exception))) { \
  310. return FAILURE; \
  311. } \
  312. return SUCCESS;
  313. static int gmp_do_operation_ex(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */
  314. {
  315. switch (opcode) {
  316. case ZEND_ADD:
  317. DO_BINARY_UI_OP(mpz_add);
  318. case ZEND_SUB:
  319. DO_BINARY_UI_OP(mpz_sub);
  320. case ZEND_MUL:
  321. DO_BINARY_UI_OP(mpz_mul);
  322. case ZEND_POW:
  323. shift_operator_helper(mpz_pow_ui, result, op1, op2, opcode);
  324. return SUCCESS;
  325. case ZEND_DIV:
  326. DO_BINARY_UI_OP_EX(mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1);
  327. case ZEND_MOD:
  328. DO_BINARY_UI_OP_EX(mpz_mod, gmp_mpz_mod_ui, 1);
  329. case ZEND_SL:
  330. shift_operator_helper(mpz_mul_2exp, result, op1, op2, opcode);
  331. return SUCCESS;
  332. case ZEND_SR:
  333. shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2, opcode);
  334. return SUCCESS;
  335. case ZEND_BW_OR:
  336. DO_BINARY_OP(mpz_ior);
  337. case ZEND_BW_AND:
  338. DO_BINARY_OP(mpz_and);
  339. case ZEND_BW_XOR:
  340. DO_BINARY_OP(mpz_xor);
  341. case ZEND_BW_NOT:
  342. DO_UNARY_OP(mpz_com);
  343. default:
  344. return FAILURE;
  345. }
  346. }
  347. /* }}} */
  348. static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */
  349. {
  350. zval op1_copy;
  351. int retval;
  352. if (result == op1) {
  353. ZVAL_COPY_VALUE(&op1_copy, op1);
  354. op1 = &op1_copy;
  355. }
  356. retval = gmp_do_operation_ex(opcode, result, op1, op2);
  357. if (retval == SUCCESS && op1 == &op1_copy) {
  358. zval_ptr_dtor(op1);
  359. }
  360. return retval;
  361. }
  362. /* }}} */
  363. static int gmp_compare(zval *op1, zval *op2) /* {{{ */
  364. {
  365. zval result;
  366. gmp_cmp(&result, op1, op2, /* is_operator */ true);
  367. /* An error/exception occurs if one of the operands is not a numeric string
  368. * or an object which is different from GMP */
  369. if (EG(exception)) {
  370. return 1;
  371. }
  372. /* result can only be a zend_long if gmp_cmp hasn't thrown an Error */
  373. ZEND_ASSERT(Z_TYPE(result) == IS_LONG);
  374. return Z_LVAL(result);
  375. }
  376. /* }}} */
  377. static int gmp_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data) /* {{{ */
  378. {
  379. mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(object);
  380. smart_str buf = {0};
  381. zval zv;
  382. php_serialize_data_t serialize_data;
  383. PHP_VAR_SERIALIZE_INIT(serialize_data);
  384. gmp_strval(&zv, gmpnum, 10);
  385. php_var_serialize(&buf, &zv, &serialize_data);
  386. zval_ptr_dtor_str(&zv);
  387. ZVAL_ARR(&zv, zend_std_get_properties(Z_OBJ_P(object)));
  388. php_var_serialize(&buf, &zv, &serialize_data);
  389. PHP_VAR_SERIALIZE_DESTROY(serialize_data);
  390. *buffer = (unsigned char *) estrndup(ZSTR_VAL(buf.s), ZSTR_LEN(buf.s));
  391. *buf_len = ZSTR_LEN(buf.s);
  392. zend_string_release_ex(buf.s, 0);
  393. return SUCCESS;
  394. }
  395. /* }}} */
  396. static int gmp_unserialize(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data) /* {{{ */
  397. {
  398. mpz_ptr gmpnum;
  399. const unsigned char *p, *max;
  400. zval *zv;
  401. int retval = FAILURE;
  402. php_unserialize_data_t unserialize_data;
  403. zend_object *zobj;
  404. PHP_VAR_UNSERIALIZE_INIT(unserialize_data);
  405. gmp_create(object, &gmpnum);
  406. zobj = Z_OBJ_P(object);
  407. p = buf;
  408. max = buf + buf_len;
  409. zv = var_tmp_var(&unserialize_data);
  410. if (!php_var_unserialize(zv, &p, max, &unserialize_data)
  411. || Z_TYPE_P(zv) != IS_STRING
  412. || convert_to_gmp(gmpnum, zv, 10, 0) == FAILURE
  413. ) {
  414. zend_throw_exception(NULL, "Could not unserialize number", 0);
  415. goto exit;
  416. }
  417. zv = var_tmp_var(&unserialize_data);
  418. if (!php_var_unserialize(zv, &p, max, &unserialize_data)
  419. || Z_TYPE_P(zv) != IS_ARRAY
  420. ) {
  421. zend_throw_exception(NULL, "Could not unserialize properties", 0);
  422. goto exit;
  423. }
  424. if (zend_hash_num_elements(Z_ARRVAL_P(zv)) != 0) {
  425. zend_hash_copy(
  426. zend_std_get_properties(zobj), Z_ARRVAL_P(zv),
  427. (copy_ctor_func_t) zval_add_ref
  428. );
  429. }
  430. retval = SUCCESS;
  431. exit:
  432. PHP_VAR_UNSERIALIZE_DESTROY(unserialize_data);
  433. return retval;
  434. }
  435. /* }}} */
  436. /* {{{ ZEND_GINIT_FUNCTION */
  437. static ZEND_GINIT_FUNCTION(gmp)
  438. {
  439. #if defined(COMPILE_DL_GMP) && defined(ZTS)
  440. ZEND_TSRMLS_CACHE_UPDATE();
  441. #endif
  442. gmp_globals->rand_initialized = 0;
  443. }
  444. /* }}} */
  445. /* {{{ ZEND_MINIT_FUNCTION */
  446. ZEND_MINIT_FUNCTION(gmp)
  447. {
  448. gmp_ce = register_class_GMP();
  449. gmp_ce->create_object = gmp_create_object;
  450. gmp_ce->serialize = gmp_serialize;
  451. gmp_ce->unserialize = gmp_unserialize;
  452. memcpy(&gmp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
  453. gmp_object_handlers.offset = XtOffsetOf(gmp_object, std);
  454. gmp_object_handlers.free_obj = gmp_free_object_storage;
  455. gmp_object_handlers.cast_object = gmp_cast_object;
  456. gmp_object_handlers.get_debug_info = gmp_get_debug_info;
  457. gmp_object_handlers.clone_obj = gmp_clone_obj;
  458. gmp_object_handlers.do_operation = gmp_do_operation;
  459. gmp_object_handlers.compare = gmp_compare;
  460. REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT);
  461. REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT);
  462. REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT);
  463. #ifdef mpir_version
  464. REGISTER_STRING_CONSTANT("GMP_MPIR_VERSION", (char *)mpir_version, CONST_CS | CONST_PERSISTENT);
  465. #endif
  466. REGISTER_STRING_CONSTANT("GMP_VERSION", (char *)gmp_version, CONST_CS | CONST_PERSISTENT);
  467. REGISTER_LONG_CONSTANT("GMP_MSW_FIRST", GMP_MSW_FIRST, CONST_CS | CONST_PERSISTENT);
  468. REGISTER_LONG_CONSTANT("GMP_LSW_FIRST", GMP_LSW_FIRST, CONST_CS | CONST_PERSISTENT);
  469. REGISTER_LONG_CONSTANT("GMP_LITTLE_ENDIAN", GMP_LITTLE_ENDIAN, CONST_CS | CONST_PERSISTENT);
  470. REGISTER_LONG_CONSTANT("GMP_BIG_ENDIAN", GMP_BIG_ENDIAN, CONST_CS | CONST_PERSISTENT);
  471. REGISTER_LONG_CONSTANT("GMP_NATIVE_ENDIAN", GMP_NATIVE_ENDIAN, CONST_CS | CONST_PERSISTENT);
  472. return SUCCESS;
  473. }
  474. /* }}} */
  475. /* {{{ ZEND_RSHUTDOWN_FUNCTION */
  476. ZEND_MODULE_DEACTIVATE_D(gmp)
  477. {
  478. if (GMPG(rand_initialized)) {
  479. gmp_randclear(GMPG(rand_state));
  480. GMPG(rand_initialized) = 0;
  481. }
  482. return SUCCESS;
  483. }
  484. /* }}} */
  485. /* {{{ ZEND_MINFO_FUNCTION */
  486. ZEND_MODULE_INFO_D(gmp)
  487. {
  488. php_info_print_table_start();
  489. php_info_print_table_row(2, "gmp support", "enabled");
  490. #ifdef mpir_version
  491. php_info_print_table_row(2, "MPIR version", mpir_version);
  492. #else
  493. php_info_print_table_row(2, "GMP version", gmp_version);
  494. #endif
  495. php_info_print_table_end();
  496. }
  497. /* }}} */
  498. static zend_result convert_zstr_to_gmp(mpz_t gmp_number, const zend_string *val, zend_long base, uint32_t arg_pos)
  499. {
  500. const char *num_str = ZSTR_VAL(val);
  501. bool skip_lead = false;
  502. if (ZSTR_LEN(val) >= 2 && num_str[0] == '0') {
  503. if ((base == 0 || base == 16) && (num_str[1] == 'x' || num_str[1] == 'X')) {
  504. base = 16;
  505. skip_lead = true;
  506. } else if ((base == 0 || base == 8) && (num_str[1] == 'o' || num_str[1] == 'O')) {
  507. base = 8;
  508. skip_lead = true;
  509. } else if ((base == 0 || base == 2) && (num_str[1] == 'b' || num_str[1] == 'B')) {
  510. base = 2;
  511. skip_lead = true;
  512. }
  513. }
  514. int gmp_ret = mpz_set_str(gmp_number, (skip_lead ? &num_str[2] : num_str), (int) base);
  515. if (-1 == gmp_ret) {
  516. if (arg_pos == 0) {
  517. zend_value_error("Number is not an integer string");
  518. } else {
  519. zend_argument_value_error(arg_pos, "is not an integer string");
  520. }
  521. return FAILURE;
  522. }
  523. return SUCCESS;
  524. }
  525. /* {{{ convert_to_gmp
  526. * Convert zval to be gmp number */
  527. static zend_result convert_to_gmp(mpz_t gmpnumber, zval *val, zend_long base, uint32_t arg_pos)
  528. {
  529. switch (Z_TYPE_P(val)) {
  530. case IS_LONG:
  531. mpz_set_si(gmpnumber, Z_LVAL_P(val));
  532. return SUCCESS;
  533. case IS_STRING: {
  534. return convert_zstr_to_gmp(gmpnumber, Z_STR_P(val), base, arg_pos);
  535. }
  536. default: {
  537. zend_long lval;
  538. if (!zend_parse_arg_long_slow(val, &lval, arg_pos)) {
  539. if (arg_pos == 0) {
  540. zend_type_error(
  541. "Number must be of type GMP|string|int, %s given", zend_zval_type_name(val));
  542. } else {
  543. zend_argument_type_error(arg_pos,
  544. "must be of type GMP|string|int, %s given", zend_zval_type_name(val));
  545. }
  546. return FAILURE;
  547. }
  548. mpz_set_si(gmpnumber, lval);
  549. return SUCCESS;
  550. }
  551. }
  552. }
  553. /* }}} */
  554. static void gmp_strval(zval *result, mpz_t gmpnum, int base) /* {{{ */
  555. {
  556. size_t num_len;
  557. zend_string *str;
  558. num_len = mpz_sizeinbase(gmpnum, abs(base));
  559. if (mpz_sgn(gmpnum) < 0) {
  560. num_len++;
  561. }
  562. str = zend_string_alloc(num_len, 0);
  563. mpz_get_str(ZSTR_VAL(str), base, gmpnum);
  564. /*
  565. * From GMP documentation for mpz_sizeinbase():
  566. * The returned value will be exact or 1 too big. If base is a power of
  567. * 2, the returned value will always be exact.
  568. *
  569. * So let's check to see if we already have a \0 byte...
  570. */
  571. if (ZSTR_VAL(str)[ZSTR_LEN(str) - 1] == '\0') {
  572. ZSTR_LEN(str)--;
  573. } else {
  574. ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
  575. }
  576. ZVAL_NEW_STR(result, str);
  577. }
  578. /* }}} */
  579. static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg, bool is_operator) /* {{{ */
  580. {
  581. mpz_ptr gmpnum_a, gmpnum_b;
  582. gmp_temp_t temp_a, temp_b;
  583. bool use_si = 0;
  584. zend_long res;
  585. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1);
  586. if (Z_TYPE_P(b_arg) == IS_LONG) {
  587. use_si = 1;
  588. temp_b.is_used = 0;
  589. } else {
  590. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2);
  591. }
  592. if (use_si) {
  593. res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg));
  594. } else {
  595. res = mpz_cmp(gmpnum_a, gmpnum_b);
  596. }
  597. FREE_GMP_TEMP(temp_a);
  598. FREE_GMP_TEMP(temp_b);
  599. RETURN_LONG(res);
  600. }
  601. /* }}} */
  602. /* {{{ gmp_zval_binary_ui_op
  603. Execute GMP binary operation.
  604. */
  605. static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, bool check_b_zero, bool is_operator)
  606. {
  607. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
  608. gmp_temp_t temp_a, temp_b;
  609. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, is_operator ? 0 : 1);
  610. if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
  611. gmpnum_b = NULL;
  612. temp_b.is_used = 0;
  613. } else {
  614. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, is_operator ? 0 : 2);
  615. }
  616. if (check_b_zero) {
  617. int b_is_zero = 0;
  618. if (!gmpnum_b) {
  619. b_is_zero = (Z_LVAL_P(b_arg) == 0);
  620. } else {
  621. b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
  622. }
  623. if (b_is_zero) {
  624. if ((gmp_binary_op_t) mpz_mod == gmp_op) {
  625. zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
  626. } else {
  627. zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
  628. }
  629. FREE_GMP_TEMP(temp_a);
  630. FREE_GMP_TEMP(temp_b);
  631. RETURN_THROWS();
  632. }
  633. }
  634. INIT_GMP_RETVAL(gmpnum_result);
  635. if (!gmpnum_b) {
  636. gmp_ui_op(gmpnum_result, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
  637. } else {
  638. gmp_op(gmpnum_result, gmpnum_a, gmpnum_b);
  639. }
  640. FREE_GMP_TEMP(temp_a);
  641. FREE_GMP_TEMP(temp_b);
  642. }
  643. /* }}} */
  644. /* {{{ gmp_zval_binary_ui_op2
  645. Execute GMP binary operation which returns 2 values.
  646. */
  647. static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero)
  648. {
  649. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2;
  650. gmp_temp_t temp_a, temp_b;
  651. zval result1, result2;
  652. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  653. if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) {
  654. gmpnum_b = NULL;
  655. temp_b.is_used = 0;
  656. } else {
  657. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  658. }
  659. if (check_b_zero) {
  660. int b_is_zero = 0;
  661. if (!gmpnum_b) {
  662. b_is_zero = (Z_LVAL_P(b_arg) == 0);
  663. } else {
  664. b_is_zero = !mpz_cmp_ui(gmpnum_b, 0);
  665. }
  666. if (b_is_zero) {
  667. zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
  668. FREE_GMP_TEMP(temp_a);
  669. FREE_GMP_TEMP(temp_b);
  670. RETURN_THROWS();
  671. }
  672. }
  673. gmp_create(&result1, &gmpnum_result1);
  674. gmp_create(&result2, &gmpnum_result2);
  675. array_init(return_value);
  676. add_next_index_zval(return_value, &result1);
  677. add_next_index_zval(return_value, &result2);
  678. if (!gmpnum_b) {
  679. gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) Z_LVAL_P(b_arg));
  680. } else {
  681. gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b);
  682. }
  683. FREE_GMP_TEMP(temp_a);
  684. FREE_GMP_TEMP(temp_b);
  685. }
  686. /* }}} */
  687. /* {{{ _gmp_binary_ui_op */
  688. static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero)
  689. {
  690. zval *a_arg, *b_arg;
  691. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  692. RETURN_THROWS();
  693. }
  694. gmp_zval_binary_ui_op(
  695. return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero, /* is_operator */ false);
  696. }
  697. /* }}} */
  698. /* Unary operations */
  699. /* {{{ gmp_zval_unary_op */
  700. static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op)
  701. {
  702. mpz_ptr gmpnum_a, gmpnum_result;
  703. gmp_temp_t temp_a;
  704. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  705. INIT_GMP_RETVAL(gmpnum_result);
  706. gmp_op(gmpnum_result, gmpnum_a);
  707. FREE_GMP_TEMP(temp_a);
  708. }
  709. /* }}} */
  710. /* {{{ _gmp_unary_op */
  711. static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op)
  712. {
  713. zval *a_arg;
  714. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  715. RETURN_THROWS();
  716. }
  717. gmp_zval_unary_op(return_value, a_arg, gmp_op);
  718. }
  719. /* }}} */
  720. /* {{{ _gmp_unary_opl */
  721. static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op)
  722. {
  723. zval *a_arg;
  724. mpz_ptr gmpnum_a;
  725. gmp_temp_t temp_a;
  726. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  727. RETURN_THROWS();
  728. }
  729. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  730. RETVAL_LONG(gmp_op(gmpnum_a));
  731. FREE_GMP_TEMP(temp_a);
  732. }
  733. /* }}} */
  734. /* {{{ Initializes GMP number */
  735. ZEND_FUNCTION(gmp_init)
  736. {
  737. mpz_ptr gmp_number;
  738. zend_string *arg_str = NULL;
  739. zend_long arg_l = 0;
  740. zend_long base = 0;
  741. ZEND_PARSE_PARAMETERS_START(1, 2)
  742. Z_PARAM_STR_OR_LONG(arg_str, arg_l)
  743. Z_PARAM_OPTIONAL
  744. Z_PARAM_LONG(base)
  745. ZEND_PARSE_PARAMETERS_END();
  746. if (base && (base < 2 || base > GMP_MAX_BASE)) {
  747. zend_argument_value_error(2, "must be between 2 and %d", GMP_MAX_BASE);
  748. RETURN_THROWS();
  749. }
  750. INIT_GMP_RETVAL(gmp_number);
  751. if (arg_str) {
  752. if (convert_zstr_to_gmp(gmp_number, arg_str, base, 1) == FAILURE) {
  753. RETURN_THROWS();
  754. }
  755. } else {
  756. mpz_set_si(gmp_number, arg_l);
  757. }
  758. }
  759. /* }}} */
  760. int gmp_import_export_validate(zend_long size, zend_long options, int *order, int *endian)
  761. {
  762. if (size < 1) {
  763. /* size argument is in second position */
  764. zend_argument_value_error(2, "must be greater than or equal to 1");
  765. return FAILURE;
  766. }
  767. switch (options & (GMP_LSW_FIRST | GMP_MSW_FIRST)) {
  768. case GMP_LSW_FIRST:
  769. *order = -1;
  770. break;
  771. case GMP_MSW_FIRST:
  772. case 0: /* default */
  773. *order = 1;
  774. break;
  775. default:
  776. /* options argument is in second position */
  777. zend_argument_value_error(3, "cannot use multiple word order options");
  778. return FAILURE;
  779. }
  780. switch (options & (GMP_LITTLE_ENDIAN | GMP_BIG_ENDIAN | GMP_NATIVE_ENDIAN)) {
  781. case GMP_LITTLE_ENDIAN:
  782. *endian = -1;
  783. break;
  784. case GMP_BIG_ENDIAN:
  785. *endian = 1;
  786. break;
  787. case GMP_NATIVE_ENDIAN:
  788. case 0: /* default */
  789. *endian = 0;
  790. break;
  791. default:
  792. /* options argument is in second position */
  793. zend_argument_value_error(3, "cannot use multiple endian options");
  794. return FAILURE;
  795. }
  796. return SUCCESS;
  797. }
  798. /* {{{ Imports a GMP number from a binary string */
  799. ZEND_FUNCTION(gmp_import)
  800. {
  801. char *data;
  802. size_t data_len;
  803. zend_long size = 1;
  804. zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
  805. int order, endian;
  806. mpz_ptr gmpnumber;
  807. if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ll", &data, &data_len, &size, &options) == FAILURE) {
  808. RETURN_THROWS();
  809. }
  810. if (gmp_import_export_validate(size, options, &order, &endian) == FAILURE) {
  811. RETURN_THROWS();
  812. }
  813. if ((data_len % size) != 0) {
  814. zend_argument_value_error(1, "must be a multiple of argument #2 ($word_size)");
  815. RETURN_THROWS();
  816. }
  817. INIT_GMP_RETVAL(gmpnumber);
  818. mpz_import(gmpnumber, data_len / size, order, size, endian, 0, data);
  819. }
  820. /* }}} */
  821. /* {{{ Exports a GMP number to a binary string */
  822. ZEND_FUNCTION(gmp_export)
  823. {
  824. zval *gmpnumber_arg;
  825. zend_long size = 1;
  826. zend_long options = GMP_MSW_FIRST | GMP_NATIVE_ENDIAN;
  827. int order, endian;
  828. mpz_ptr gmpnumber;
  829. gmp_temp_t temp_a;
  830. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &gmpnumber_arg, &size, &options) == FAILURE) {
  831. RETURN_THROWS();
  832. }
  833. if (gmp_import_export_validate(size, options, &order, &endian) == FAILURE) {
  834. RETURN_THROWS();
  835. }
  836. FETCH_GMP_ZVAL(gmpnumber, gmpnumber_arg, temp_a, 1);
  837. if (mpz_sgn(gmpnumber) == 0) {
  838. RETVAL_EMPTY_STRING();
  839. } else {
  840. size_t bits_per_word = size * 8;
  841. size_t count = (mpz_sizeinbase(gmpnumber, 2) + bits_per_word - 1) / bits_per_word;
  842. zend_string *out_string = zend_string_safe_alloc(count, size, 0, 0);
  843. mpz_export(ZSTR_VAL(out_string), NULL, order, size, endian, 0, gmpnumber);
  844. ZSTR_VAL(out_string)[ZSTR_LEN(out_string)] = '\0';
  845. RETVAL_NEW_STR(out_string);
  846. }
  847. FREE_GMP_TEMP(temp_a);
  848. }
  849. /* }}} */
  850. /* {{{ Gets signed long value of GMP number */
  851. ZEND_FUNCTION(gmp_intval)
  852. {
  853. zval *gmpnumber_arg;
  854. mpz_ptr gmpnum;
  855. gmp_temp_t temp_a;
  856. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &gmpnumber_arg) == FAILURE){
  857. RETURN_THROWS();
  858. }
  859. FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1);
  860. RETVAL_LONG(mpz_get_si(gmpnum));
  861. FREE_GMP_TEMP(temp_a);
  862. }
  863. /* }}} */
  864. /* {{{ Gets string representation of GMP number */
  865. ZEND_FUNCTION(gmp_strval)
  866. {
  867. zval *gmpnumber_arg;
  868. zend_long base = 10;
  869. mpz_ptr gmpnum;
  870. gmp_temp_t temp_a;
  871. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &base) == FAILURE) {
  872. RETURN_THROWS();
  873. }
  874. /* Although the maximum base in general in GMP is 62, mpz_get_str()
  875. * is explicitly limited to -36 when dealing with negative bases. */
  876. if ((base < 2 && base > -2) || base > GMP_MAX_BASE || base < -36) {
  877. zend_argument_value_error(2, "must be between 2 and %d, or -2 and -36", GMP_MAX_BASE);
  878. RETURN_THROWS();
  879. }
  880. FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a, 1);
  881. gmp_strval(return_value, gmpnum, (int)base);
  882. FREE_GMP_TEMP(temp_a);
  883. }
  884. /* }}} */
  885. /* {{{ Add a and b */
  886. ZEND_FUNCTION(gmp_add)
  887. {
  888. gmp_binary_ui_op(mpz_add, mpz_add_ui);
  889. }
  890. /* }}} */
  891. /* {{{ Subtract b from a */
  892. ZEND_FUNCTION(gmp_sub)
  893. {
  894. gmp_binary_ui_op(mpz_sub, mpz_sub_ui);
  895. }
  896. /* }}} */
  897. /* {{{ Multiply a and b */
  898. ZEND_FUNCTION(gmp_mul)
  899. {
  900. gmp_binary_ui_op(mpz_mul, mpz_mul_ui);
  901. }
  902. /* }}} */
  903. /* {{{ Divide a by b, returns quotient and reminder */
  904. ZEND_FUNCTION(gmp_div_qr)
  905. {
  906. zval *a_arg, *b_arg;
  907. zend_long round = GMP_ROUND_ZERO;
  908. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
  909. RETURN_THROWS();
  910. }
  911. switch (round) {
  912. case GMP_ROUND_ZERO:
  913. gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, mpz_tdiv_qr_ui, 1);
  914. break;
  915. case GMP_ROUND_PLUSINF:
  916. gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, mpz_cdiv_qr_ui, 1);
  917. break;
  918. case GMP_ROUND_MINUSINF:
  919. gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, mpz_fdiv_qr_ui, 1);
  920. break;
  921. default:
  922. zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
  923. RETURN_THROWS();
  924. }
  925. }
  926. /* }}} */
  927. /* {{{ Divide a by b, returns reminder only */
  928. ZEND_FUNCTION(gmp_div_r)
  929. {
  930. zval *a_arg, *b_arg;
  931. zend_long round = GMP_ROUND_ZERO;
  932. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
  933. RETURN_THROWS();
  934. }
  935. switch (round) {
  936. case GMP_ROUND_ZERO:
  937. gmp_zval_binary_ui_op(
  938. return_value, a_arg, b_arg, mpz_tdiv_r, gmp_mpz_tdiv_r_ui, 1, /* is_operator */ false);
  939. break;
  940. case GMP_ROUND_PLUSINF:
  941. gmp_zval_binary_ui_op(
  942. return_value, a_arg, b_arg, mpz_cdiv_r, gmp_mpz_cdiv_r_ui, 1, /* is_operator */ false);
  943. break;
  944. case GMP_ROUND_MINUSINF:
  945. gmp_zval_binary_ui_op(
  946. return_value, a_arg, b_arg, mpz_fdiv_r, gmp_mpz_fdiv_r_ui, 1, /* is_operator */ false);
  947. break;
  948. default:
  949. zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
  950. RETURN_THROWS();
  951. }
  952. }
  953. /* }}} */
  954. /* {{{ Divide a by b, returns quotient only */
  955. ZEND_FUNCTION(gmp_div_q)
  956. {
  957. zval *a_arg, *b_arg;
  958. zend_long round = GMP_ROUND_ZERO;
  959. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz|l", &a_arg, &b_arg, &round) == FAILURE) {
  960. RETURN_THROWS();
  961. }
  962. switch (round) {
  963. case GMP_ROUND_ZERO:
  964. gmp_zval_binary_ui_op(
  965. return_value, a_arg, b_arg, mpz_tdiv_q, gmp_mpz_tdiv_q_ui, 1, /* is_operator */ false);
  966. break;
  967. case GMP_ROUND_PLUSINF:
  968. gmp_zval_binary_ui_op(
  969. return_value, a_arg, b_arg, mpz_cdiv_q, gmp_mpz_cdiv_q_ui, 1, /* is_operator */ false);
  970. break;
  971. case GMP_ROUND_MINUSINF:
  972. gmp_zval_binary_ui_op(
  973. return_value, a_arg, b_arg, mpz_fdiv_q, gmp_mpz_fdiv_q_ui, 1, /* is_operator */ false);
  974. break;
  975. default:
  976. zend_argument_value_error(3, "must be one of GMP_ROUND_ZERO, GMP_ROUND_PLUSINF, or GMP_ROUND_MINUSINF");
  977. RETURN_THROWS();
  978. }
  979. }
  980. /* }}} */
  981. /* {{{ Computes a modulo b */
  982. ZEND_FUNCTION(gmp_mod)
  983. {
  984. gmp_binary_ui_op_no_zero(mpz_mod, gmp_mpz_mod_ui);
  985. }
  986. /* }}} */
  987. /* {{{ Divide a by b using exact division algorithm */
  988. ZEND_FUNCTION(gmp_divexact)
  989. {
  990. gmp_binary_ui_op_no_zero(mpz_divexact, NULL);
  991. }
  992. /* }}} */
  993. /* {{{ Negates a number */
  994. ZEND_FUNCTION(gmp_neg)
  995. {
  996. gmp_unary_op(mpz_neg);
  997. }
  998. /* }}} */
  999. /* {{{ Calculates absolute value */
  1000. ZEND_FUNCTION(gmp_abs)
  1001. {
  1002. gmp_unary_op(mpz_abs);
  1003. }
  1004. /* }}} */
  1005. /* {{{ Calculates factorial function */
  1006. ZEND_FUNCTION(gmp_fact)
  1007. {
  1008. zval *a_arg;
  1009. mpz_ptr gmpnum_result;
  1010. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  1011. RETURN_THROWS();
  1012. }
  1013. if (Z_TYPE_P(a_arg) == IS_LONG) {
  1014. if (Z_LVAL_P(a_arg) < 0) {
  1015. zend_argument_value_error(1, "must be greater than or equal to 0");
  1016. RETURN_THROWS();
  1017. }
  1018. } else {
  1019. mpz_ptr gmpnum;
  1020. gmp_temp_t temp_a;
  1021. FETCH_GMP_ZVAL(gmpnum, a_arg, temp_a, 1);
  1022. FREE_GMP_TEMP(temp_a);
  1023. if (mpz_sgn(gmpnum) < 0) {
  1024. zend_argument_value_error(1, "must be greater than or equal to 0");
  1025. RETURN_THROWS();
  1026. }
  1027. }
  1028. INIT_GMP_RETVAL(gmpnum_result);
  1029. mpz_fac_ui(gmpnum_result, zval_get_long(a_arg));
  1030. }
  1031. /* }}} */
  1032. /* {{{ Calculates binomial coefficient */
  1033. ZEND_FUNCTION(gmp_binomial)
  1034. {
  1035. zval *n_arg;
  1036. zend_long k;
  1037. mpz_ptr gmpnum_result;
  1038. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &n_arg, &k) == FAILURE) {
  1039. RETURN_THROWS();
  1040. }
  1041. if (k < 0) {
  1042. zend_argument_value_error(2, "must be greater than or equal to 0");
  1043. RETURN_THROWS();
  1044. }
  1045. INIT_GMP_RETVAL(gmpnum_result);
  1046. if (Z_TYPE_P(n_arg) == IS_LONG && Z_LVAL_P(n_arg) >= 0) {
  1047. mpz_bin_uiui(gmpnum_result, (gmp_ulong) Z_LVAL_P(n_arg), (gmp_ulong) k);
  1048. } else {
  1049. mpz_ptr gmpnum_n;
  1050. gmp_temp_t temp_n;
  1051. FETCH_GMP_ZVAL(gmpnum_n, n_arg, temp_n, 1);
  1052. mpz_bin_ui(gmpnum_result, gmpnum_n, (gmp_ulong) k);
  1053. FREE_GMP_TEMP(temp_n);
  1054. }
  1055. }
  1056. /* }}} */
  1057. /* {{{ Raise base to power exp */
  1058. ZEND_FUNCTION(gmp_pow)
  1059. {
  1060. zval *base_arg;
  1061. mpz_ptr gmpnum_result;
  1062. gmp_temp_t temp_base;
  1063. zend_long exp;
  1064. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &base_arg, &exp) == FAILURE) {
  1065. RETURN_THROWS();
  1066. }
  1067. if (exp < 0) {
  1068. zend_argument_value_error(2, "must be greater than or equal to 0");
  1069. RETURN_THROWS();
  1070. }
  1071. if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) {
  1072. INIT_GMP_RETVAL(gmpnum_result);
  1073. mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp);
  1074. } else {
  1075. mpz_ptr gmpnum_base;
  1076. FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1);
  1077. INIT_GMP_RETVAL(gmpnum_result);
  1078. mpz_pow_ui(gmpnum_result, gmpnum_base, exp);
  1079. FREE_GMP_TEMP(temp_base);
  1080. }
  1081. }
  1082. /* }}} */
  1083. /* {{{ Raise base to power exp and take result modulo mod */
  1084. ZEND_FUNCTION(gmp_powm)
  1085. {
  1086. zval *base_arg, *exp_arg, *mod_arg;
  1087. mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result;
  1088. int use_ui = 0;
  1089. gmp_temp_t temp_base, temp_exp, temp_mod;
  1090. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){
  1091. RETURN_THROWS();
  1092. }
  1093. FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1);
  1094. if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) {
  1095. use_ui = 1;
  1096. temp_exp.is_used = 0;
  1097. } else {
  1098. FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base, 2);
  1099. if (mpz_sgn(gmpnum_exp) < 0) {
  1100. zend_argument_value_error(2, "must be greater than or equal to 0");
  1101. FREE_GMP_TEMP(temp_base);
  1102. FREE_GMP_TEMP(temp_exp);
  1103. RETURN_THROWS();
  1104. }
  1105. }
  1106. FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base, 3);
  1107. if (!mpz_cmp_ui(gmpnum_mod, 0)) {
  1108. zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
  1109. FREE_GMP_TEMP(temp_base);
  1110. FREE_GMP_TEMP(temp_exp);
  1111. FREE_GMP_TEMP(temp_mod);
  1112. RETURN_THROWS();
  1113. }
  1114. INIT_GMP_RETVAL(gmpnum_result);
  1115. if (use_ui) {
  1116. mpz_powm_ui(gmpnum_result, gmpnum_base, (zend_ulong) Z_LVAL_P(exp_arg), gmpnum_mod);
  1117. } else {
  1118. mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod);
  1119. FREE_GMP_TEMP(temp_exp);
  1120. }
  1121. FREE_GMP_TEMP(temp_base);
  1122. FREE_GMP_TEMP(temp_mod);
  1123. }
  1124. /* }}} */
  1125. /* {{{ Takes integer part of square root of a */
  1126. ZEND_FUNCTION(gmp_sqrt)
  1127. {
  1128. zval *a_arg;
  1129. mpz_ptr gmpnum_a, gmpnum_result;
  1130. gmp_temp_t temp_a;
  1131. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  1132. RETURN_THROWS();
  1133. }
  1134. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1135. if (mpz_sgn(gmpnum_a) < 0) {
  1136. zend_argument_value_error(1, "must be greater than or equal to 0");
  1137. FREE_GMP_TEMP(temp_a);
  1138. RETURN_THROWS();
  1139. }
  1140. INIT_GMP_RETVAL(gmpnum_result);
  1141. mpz_sqrt(gmpnum_result, gmpnum_a);
  1142. FREE_GMP_TEMP(temp_a);
  1143. }
  1144. /* }}} */
  1145. /* {{{ Square root with remainder */
  1146. ZEND_FUNCTION(gmp_sqrtrem)
  1147. {
  1148. zval *a_arg;
  1149. mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
  1150. gmp_temp_t temp_a;
  1151. zval result1, result2;
  1152. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  1153. RETURN_THROWS();
  1154. }
  1155. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1156. if (mpz_sgn(gmpnum_a) < 0) {
  1157. zend_argument_value_error(1, "must be greater than or equal to 0");
  1158. FREE_GMP_TEMP(temp_a);
  1159. RETURN_THROWS();
  1160. }
  1161. gmp_create(&result1, &gmpnum_result1);
  1162. gmp_create(&result2, &gmpnum_result2);
  1163. array_init(return_value);
  1164. add_next_index_zval(return_value, &result1);
  1165. add_next_index_zval(return_value, &result2);
  1166. mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a);
  1167. FREE_GMP_TEMP(temp_a);
  1168. }
  1169. /* }}} */
  1170. /* {{{ Takes integer part of nth root */
  1171. ZEND_FUNCTION(gmp_root)
  1172. {
  1173. zval *a_arg;
  1174. zend_long nth;
  1175. mpz_ptr gmpnum_a, gmpnum_result;
  1176. gmp_temp_t temp_a;
  1177. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
  1178. RETURN_THROWS();
  1179. }
  1180. if (nth <= 0) {
  1181. zend_argument_value_error(2, "must be greater than 0");
  1182. RETURN_THROWS();
  1183. }
  1184. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1185. if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
  1186. zend_argument_value_error(2, "must be odd if argument #1 ($a) is negative");
  1187. FREE_GMP_TEMP(temp_a);
  1188. RETURN_THROWS();
  1189. }
  1190. INIT_GMP_RETVAL(gmpnum_result);
  1191. mpz_root(gmpnum_result, gmpnum_a, (gmp_ulong) nth);
  1192. FREE_GMP_TEMP(temp_a);
  1193. }
  1194. /* }}} */
  1195. /* {{{ Calculates integer part of nth root and remainder */
  1196. ZEND_FUNCTION(gmp_rootrem)
  1197. {
  1198. zval *a_arg;
  1199. zend_long nth;
  1200. mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2;
  1201. gmp_temp_t temp_a;
  1202. zval result1, result2;
  1203. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &nth) == FAILURE) {
  1204. RETURN_THROWS();
  1205. }
  1206. if (nth <= 0) {
  1207. zend_argument_value_error(2, "must be greater than or equal to 1");
  1208. RETURN_THROWS();
  1209. }
  1210. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1211. if (nth % 2 == 0 && mpz_sgn(gmpnum_a) < 0) {
  1212. zend_argument_value_error(2, "must be odd if argument #1 ($a) is negative");
  1213. FREE_GMP_TEMP(temp_a);
  1214. RETURN_THROWS();
  1215. }
  1216. gmp_create(&result1, &gmpnum_result1);
  1217. gmp_create(&result2, &gmpnum_result2);
  1218. array_init(return_value);
  1219. add_next_index_zval(return_value, &result1);
  1220. add_next_index_zval(return_value, &result2);
  1221. #if GMP_51_OR_NEWER
  1222. /* mpz_rootrem() is supported since GMP 4.2, but buggy wrt odd roots
  1223. * of negative numbers */
  1224. mpz_rootrem(gmpnum_result1, gmpnum_result2, gmpnum_a, (gmp_ulong) nth);
  1225. #else
  1226. mpz_root(gmpnum_result1, gmpnum_a, (gmp_ulong) nth);
  1227. mpz_pow_ui(gmpnum_result2, gmpnum_result1, (gmp_ulong) nth);
  1228. mpz_sub(gmpnum_result2, gmpnum_a, gmpnum_result2);
  1229. #endif
  1230. FREE_GMP_TEMP(temp_a);
  1231. }
  1232. /* }}} */
  1233. /* {{{ Checks if a is an exact square */
  1234. ZEND_FUNCTION(gmp_perfect_square)
  1235. {
  1236. zval *a_arg;
  1237. mpz_ptr gmpnum_a;
  1238. gmp_temp_t temp_a;
  1239. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  1240. RETURN_THROWS();
  1241. }
  1242. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1243. RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0));
  1244. FREE_GMP_TEMP(temp_a);
  1245. }
  1246. /* }}} */
  1247. /* {{{ Checks if a is a perfect power */
  1248. ZEND_FUNCTION(gmp_perfect_power)
  1249. {
  1250. zval *a_arg;
  1251. mpz_ptr gmpnum_a;
  1252. gmp_temp_t temp_a;
  1253. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  1254. RETURN_THROWS();
  1255. }
  1256. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1257. RETVAL_BOOL((mpz_perfect_power_p(gmpnum_a) != 0));
  1258. FREE_GMP_TEMP(temp_a);
  1259. }
  1260. /* }}} */
  1261. /* {{{ Checks if a is "probably prime" */
  1262. ZEND_FUNCTION(gmp_prob_prime)
  1263. {
  1264. zval *gmpnumber_arg;
  1265. mpz_ptr gmpnum_a;
  1266. zend_long reps = 10;
  1267. gmp_temp_t temp_a;
  1268. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|l", &gmpnumber_arg, &reps) == FAILURE) {
  1269. RETURN_THROWS();
  1270. }
  1271. FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a, 1);
  1272. RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, (int)reps));
  1273. FREE_GMP_TEMP(temp_a);
  1274. }
  1275. /* }}} */
  1276. /* {{{ Computes greatest common denominator (gcd) of a and b */
  1277. ZEND_FUNCTION(gmp_gcd)
  1278. {
  1279. gmp_binary_ui_op(mpz_gcd, gmp_mpz_gcd_ui);
  1280. }
  1281. /* }}} */
  1282. /* {{{ Computes least common multiple (lcm) of a and b */
  1283. ZEND_FUNCTION(gmp_lcm)
  1284. {
  1285. gmp_binary_ui_op(mpz_lcm, mpz_lcm_ui);
  1286. }
  1287. /* }}} */
  1288. /* {{{ Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */
  1289. ZEND_FUNCTION(gmp_gcdext)
  1290. {
  1291. zval *a_arg, *b_arg;
  1292. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g;
  1293. gmp_temp_t temp_a, temp_b;
  1294. zval result_g, result_s, result_t;
  1295. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1296. RETURN_THROWS();
  1297. }
  1298. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1299. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  1300. gmp_create(&result_g, &gmpnum_g);
  1301. gmp_create(&result_s, &gmpnum_s);
  1302. gmp_create(&result_t, &gmpnum_t);
  1303. array_init(return_value);
  1304. add_assoc_zval(return_value, "g", &result_g);
  1305. add_assoc_zval(return_value, "s", &result_s);
  1306. add_assoc_zval(return_value, "t", &result_t);
  1307. mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b);
  1308. FREE_GMP_TEMP(temp_a);
  1309. FREE_GMP_TEMP(temp_b);
  1310. }
  1311. /* }}} */
  1312. /* {{{ Computes the inverse of a modulo b */
  1313. ZEND_FUNCTION(gmp_invert)
  1314. {
  1315. zval *a_arg, *b_arg;
  1316. mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result;
  1317. gmp_temp_t temp_a, temp_b;
  1318. int res;
  1319. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1320. RETURN_THROWS();
  1321. }
  1322. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1323. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  1324. // TODO Early check if b_arg IS_LONG?
  1325. if (0 == mpz_cmp_ui(gmpnum_b, 0)) {
  1326. zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
  1327. FREE_GMP_TEMP(temp_a);
  1328. FREE_GMP_TEMP(temp_b);
  1329. RETURN_THROWS();
  1330. }
  1331. INIT_GMP_RETVAL(gmpnum_result);
  1332. res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b);
  1333. FREE_GMP_TEMP(temp_a);
  1334. FREE_GMP_TEMP(temp_b);
  1335. if (!res) {
  1336. zval_ptr_dtor(return_value);
  1337. RETURN_FALSE;
  1338. }
  1339. }
  1340. /* }}} */
  1341. /* {{{ Computes Jacobi symbol */
  1342. ZEND_FUNCTION(gmp_jacobi)
  1343. {
  1344. zval *a_arg, *b_arg;
  1345. mpz_ptr gmpnum_a, gmpnum_b;
  1346. gmp_temp_t temp_a, temp_b;
  1347. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1348. RETURN_THROWS();
  1349. }
  1350. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1351. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  1352. RETVAL_LONG(mpz_jacobi(gmpnum_a, gmpnum_b));
  1353. FREE_GMP_TEMP(temp_a);
  1354. FREE_GMP_TEMP(temp_b);
  1355. }
  1356. /* }}} */
  1357. /* {{{ Computes Legendre symbol */
  1358. ZEND_FUNCTION(gmp_legendre)
  1359. {
  1360. zval *a_arg, *b_arg;
  1361. mpz_ptr gmpnum_a, gmpnum_b;
  1362. gmp_temp_t temp_a, temp_b;
  1363. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1364. RETURN_THROWS();
  1365. }
  1366. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1367. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  1368. RETVAL_LONG(mpz_legendre(gmpnum_a, gmpnum_b));
  1369. FREE_GMP_TEMP(temp_a);
  1370. FREE_GMP_TEMP(temp_b);
  1371. }
  1372. /* }}} */
  1373. /* {{{ Computes the Kronecker symbol */
  1374. ZEND_FUNCTION(gmp_kronecker)
  1375. {
  1376. zval *a_arg, *b_arg;
  1377. mpz_ptr gmpnum_a, gmpnum_b;
  1378. gmp_temp_t temp_a, temp_b;
  1379. bool use_a_si = 0, use_b_si = 0;
  1380. int result;
  1381. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1382. RETURN_THROWS();
  1383. }
  1384. if (Z_TYPE_P(a_arg) == IS_LONG && Z_TYPE_P(b_arg) != IS_LONG) {
  1385. use_a_si = 1;
  1386. temp_a.is_used = 0;
  1387. } else {
  1388. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1389. }
  1390. if (Z_TYPE_P(b_arg) == IS_LONG) {
  1391. use_b_si = 1;
  1392. temp_b.is_used = 0;
  1393. } else {
  1394. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  1395. }
  1396. if (use_a_si) {
  1397. ZEND_ASSERT(use_b_si == 0);
  1398. result = mpz_si_kronecker((gmp_long) Z_LVAL_P(a_arg), gmpnum_b);
  1399. } else if (use_b_si) {
  1400. result = mpz_kronecker_si(gmpnum_a, (gmp_long) Z_LVAL_P(b_arg));
  1401. } else {
  1402. result = mpz_kronecker(gmpnum_a, gmpnum_b);
  1403. }
  1404. FREE_GMP_TEMP(temp_a);
  1405. FREE_GMP_TEMP(temp_b);
  1406. RETURN_LONG(result);
  1407. }
  1408. /* }}} */
  1409. /* {{{ Compares two numbers */
  1410. ZEND_FUNCTION(gmp_cmp)
  1411. {
  1412. zval *a_arg, *b_arg;
  1413. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1414. RETURN_THROWS();
  1415. }
  1416. gmp_cmp(return_value, a_arg, b_arg, /* is_operator */ false);
  1417. }
  1418. /* }}} */
  1419. /* {{{ Gets the sign of the number */
  1420. ZEND_FUNCTION(gmp_sign)
  1421. {
  1422. /* Can't use gmp_unary_opl here, because mpz_sgn is a macro */
  1423. zval *a_arg;
  1424. mpz_ptr gmpnum_a;
  1425. gmp_temp_t temp_a;
  1426. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &a_arg) == FAILURE){
  1427. RETURN_THROWS();
  1428. }
  1429. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1430. RETVAL_LONG(mpz_sgn(gmpnum_a));
  1431. FREE_GMP_TEMP(temp_a);
  1432. }
  1433. /* }}} */
  1434. static void gmp_init_random(void)
  1435. {
  1436. if (!GMPG(rand_initialized)) {
  1437. /* Initialize */
  1438. gmp_randinit_mt(GMPG(rand_state));
  1439. /* Seed */
  1440. gmp_randseed_ui(GMPG(rand_state), GENERATE_SEED());
  1441. GMPG(rand_initialized) = 1;
  1442. }
  1443. }
  1444. /* {{{ Seed the RNG */
  1445. ZEND_FUNCTION(gmp_random_seed)
  1446. {
  1447. zval *seed;
  1448. gmp_temp_t temp_a;
  1449. if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &seed) == FAILURE) {
  1450. RETURN_THROWS();
  1451. }
  1452. gmp_init_random();
  1453. if (Z_TYPE_P(seed) == IS_LONG && Z_LVAL_P(seed) >= 0) {
  1454. gmp_randseed_ui(GMPG(rand_state), Z_LVAL_P(seed));
  1455. }
  1456. else {
  1457. mpz_ptr gmpnum_seed;
  1458. FETCH_GMP_ZVAL(gmpnum_seed, seed, temp_a, 1);
  1459. gmp_randseed(GMPG(rand_state), gmpnum_seed);
  1460. FREE_GMP_TEMP(temp_a);
  1461. }
  1462. }
  1463. /* }}} */
  1464. /* {{{ Gets a random number in the range 0 to (2 ** n) - 1 */
  1465. ZEND_FUNCTION(gmp_random_bits)
  1466. {
  1467. zend_long bits;
  1468. mpz_ptr gmpnum_result;
  1469. if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &bits) == FAILURE) {
  1470. RETURN_THROWS();
  1471. }
  1472. if (bits <= 0) {
  1473. zend_argument_value_error(1, "must be greater than or equal to 1");
  1474. RETURN_THROWS();
  1475. }
  1476. INIT_GMP_RETVAL(gmpnum_result);
  1477. gmp_init_random();
  1478. mpz_urandomb(gmpnum_result, GMPG(rand_state), bits);
  1479. }
  1480. /* }}} */
  1481. /* {{{ Gets a random number in the range min to max */
  1482. ZEND_FUNCTION(gmp_random_range)
  1483. {
  1484. zval *min_arg, *max_arg;
  1485. mpz_ptr gmpnum_max, gmpnum_result;
  1486. mpz_t gmpnum_range;
  1487. gmp_temp_t temp_a, temp_b;
  1488. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &min_arg, &max_arg) == FAILURE) {
  1489. RETURN_THROWS();
  1490. }
  1491. gmp_init_random();
  1492. FETCH_GMP_ZVAL(gmpnum_max, max_arg, temp_a, 2);
  1493. if (Z_TYPE_P(min_arg) == IS_LONG && Z_LVAL_P(min_arg) >= 0) {
  1494. if (mpz_cmp_ui(gmpnum_max, Z_LVAL_P(min_arg)) <= 0) {
  1495. FREE_GMP_TEMP(temp_a);
  1496. zend_argument_value_error(1, "must be less than argument #2 ($maximum)");
  1497. RETURN_THROWS();
  1498. }
  1499. INIT_GMP_RETVAL(gmpnum_result);
  1500. mpz_init(gmpnum_range);
  1501. if (Z_LVAL_P(min_arg) != 0) {
  1502. mpz_sub_ui(gmpnum_range, gmpnum_max, Z_LVAL_P(min_arg) - 1);
  1503. } else {
  1504. mpz_add_ui(gmpnum_range, gmpnum_max, 1);
  1505. }
  1506. mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
  1507. if (Z_LVAL_P(min_arg) != 0) {
  1508. mpz_add_ui(gmpnum_result, gmpnum_result, Z_LVAL_P(min_arg));
  1509. }
  1510. mpz_clear(gmpnum_range);
  1511. FREE_GMP_TEMP(temp_a);
  1512. } else {
  1513. mpz_ptr gmpnum_min;
  1514. FETCH_GMP_ZVAL_DEP(gmpnum_min, min_arg, temp_b, temp_a, 1);
  1515. if (mpz_cmp(gmpnum_max, gmpnum_min) <= 0) {
  1516. FREE_GMP_TEMP(temp_b);
  1517. FREE_GMP_TEMP(temp_a);
  1518. zend_argument_value_error(1, "must be less than argument #2 ($maximum)");
  1519. RETURN_THROWS();
  1520. }
  1521. INIT_GMP_RETVAL(gmpnum_result);
  1522. mpz_init(gmpnum_range);
  1523. mpz_sub(gmpnum_range, gmpnum_max, gmpnum_min);
  1524. mpz_add_ui(gmpnum_range, gmpnum_range, 1);
  1525. mpz_urandomm(gmpnum_result, GMPG(rand_state), gmpnum_range);
  1526. mpz_add(gmpnum_result, gmpnum_result, gmpnum_min);
  1527. mpz_clear(gmpnum_range);
  1528. FREE_GMP_TEMP(temp_b);
  1529. FREE_GMP_TEMP(temp_a);
  1530. }
  1531. }
  1532. /* }}} */
  1533. /* {{{ Calculates logical AND of a and b */
  1534. ZEND_FUNCTION(gmp_and)
  1535. {
  1536. gmp_binary_op(mpz_and);
  1537. }
  1538. /* }}} */
  1539. /* {{{ Calculates logical OR of a and b */
  1540. ZEND_FUNCTION(gmp_or)
  1541. {
  1542. gmp_binary_op(mpz_ior);
  1543. }
  1544. /* }}} */
  1545. /* {{{ Calculates one's complement of a */
  1546. ZEND_FUNCTION(gmp_com)
  1547. {
  1548. gmp_unary_op(mpz_com);
  1549. }
  1550. /* }}} */
  1551. /* {{{ Finds next prime of a */
  1552. ZEND_FUNCTION(gmp_nextprime)
  1553. {
  1554. gmp_unary_op(mpz_nextprime);
  1555. }
  1556. /* }}} */
  1557. /* {{{ Calculates logical exclusive OR of a and b */
  1558. ZEND_FUNCTION(gmp_xor)
  1559. {
  1560. gmp_binary_op(mpz_xor);
  1561. }
  1562. /* }}} */
  1563. /* {{{ Sets or clear bit in a */
  1564. ZEND_FUNCTION(gmp_setbit)
  1565. {
  1566. zval *a_arg;
  1567. zend_long index;
  1568. bool set = 1;
  1569. mpz_ptr gmpnum_a;
  1570. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) {
  1571. RETURN_THROWS();
  1572. }
  1573. if (index < 0) {
  1574. zend_argument_value_error(2, "must be greater than or equal to 0");
  1575. RETURN_THROWS();
  1576. }
  1577. if (index / GMP_NUMB_BITS >= INT_MAX) {
  1578. zend_argument_value_error(2, "must be less than %d * %d", INT_MAX, GMP_NUMB_BITS);
  1579. RETURN_THROWS();
  1580. }
  1581. gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
  1582. if (set) {
  1583. mpz_setbit(gmpnum_a, index);
  1584. } else {
  1585. mpz_clrbit(gmpnum_a, index);
  1586. }
  1587. }
  1588. /* }}} */
  1589. /* {{{ Clears bit in a */
  1590. ZEND_FUNCTION(gmp_clrbit)
  1591. {
  1592. zval *a_arg;
  1593. zend_long index;
  1594. mpz_ptr gmpnum_a;
  1595. if (zend_parse_parameters(ZEND_NUM_ARGS(), "Ol", &a_arg, gmp_ce, &index) == FAILURE){
  1596. RETURN_THROWS();
  1597. }
  1598. if (index < 0) {
  1599. zend_argument_value_error(2, "must be greater than or equal to 0");
  1600. RETURN_THROWS();
  1601. }
  1602. gmpnum_a = GET_GMP_FROM_ZVAL(a_arg);
  1603. mpz_clrbit(gmpnum_a, index);
  1604. }
  1605. /* }}} */
  1606. /* {{{ Tests if bit is set in a */
  1607. ZEND_FUNCTION(gmp_testbit)
  1608. {
  1609. zval *a_arg;
  1610. zend_long index;
  1611. mpz_ptr gmpnum_a;
  1612. gmp_temp_t temp_a;
  1613. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &index) == FAILURE){
  1614. RETURN_THROWS();
  1615. }
  1616. if (index < 0) {
  1617. zend_argument_value_error(2, "must be greater than or equal to 0");
  1618. RETURN_THROWS();
  1619. }
  1620. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1621. RETVAL_BOOL(mpz_tstbit(gmpnum_a, index));
  1622. FREE_GMP_TEMP(temp_a);
  1623. }
  1624. /* }}} */
  1625. /* {{{ Calculates the population count of a */
  1626. ZEND_FUNCTION(gmp_popcount)
  1627. {
  1628. gmp_unary_opl(mpz_popcount);
  1629. }
  1630. /* }}} */
  1631. /* {{{ Calculates hamming distance between a and b */
  1632. ZEND_FUNCTION(gmp_hamdist)
  1633. {
  1634. zval *a_arg, *b_arg;
  1635. mpz_ptr gmpnum_a, gmpnum_b;
  1636. gmp_temp_t temp_a, temp_b;
  1637. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &a_arg, &b_arg) == FAILURE){
  1638. RETURN_THROWS();
  1639. }
  1640. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1641. FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a, 2);
  1642. RETVAL_LONG(mpz_hamdist(gmpnum_a, gmpnum_b));
  1643. FREE_GMP_TEMP(temp_a);
  1644. FREE_GMP_TEMP(temp_b);
  1645. }
  1646. /* }}} */
  1647. /* {{{ Finds first zero bit */
  1648. ZEND_FUNCTION(gmp_scan0)
  1649. {
  1650. zval *a_arg;
  1651. mpz_ptr gmpnum_a;
  1652. gmp_temp_t temp_a;
  1653. zend_long start;
  1654. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
  1655. RETURN_THROWS();
  1656. }
  1657. if (start < 0) {
  1658. zend_argument_value_error(2, "must be greater than or equal to 0");
  1659. RETURN_THROWS();
  1660. }
  1661. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1662. RETVAL_LONG(mpz_scan0(gmpnum_a, start));
  1663. FREE_GMP_TEMP(temp_a);
  1664. }
  1665. /* }}} */
  1666. /* {{{ Finds first non-zero bit */
  1667. ZEND_FUNCTION(gmp_scan1)
  1668. {
  1669. zval *a_arg;
  1670. mpz_ptr gmpnum_a;
  1671. gmp_temp_t temp_a;
  1672. zend_long start;
  1673. if (zend_parse_parameters(ZEND_NUM_ARGS(), "zl", &a_arg, &start) == FAILURE){
  1674. RETURN_THROWS();
  1675. }
  1676. if (start < 0) {
  1677. zend_argument_value_error(2, "must be greater than or equal to 0");
  1678. RETURN_THROWS();
  1679. }
  1680. FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a, 1);
  1681. RETVAL_LONG(mpz_scan1(gmpnum_a, start));
  1682. FREE_GMP_TEMP(temp_a);
  1683. }
  1684. /* }}} */
  1685. ZEND_METHOD(GMP, __serialize)
  1686. {
  1687. ZEND_PARSE_PARAMETERS_NONE();
  1688. zval zv;
  1689. array_init(return_value);
  1690. mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(ZEND_THIS);
  1691. gmp_strval(&zv, gmpnum, 16);
  1692. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &zv);
  1693. HashTable *props = Z_OBJ_P(ZEND_THIS)->properties;
  1694. if (props && zend_hash_num_elements(props) != 0) {
  1695. ZVAL_ARR(&zv, zend_proptable_to_symtable(
  1696. zend_std_get_properties(Z_OBJ_P(ZEND_THIS)), /* always duplicate */ 1));
  1697. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &zv);
  1698. }
  1699. }
  1700. ZEND_METHOD(GMP, __unserialize)
  1701. {
  1702. HashTable *data;
  1703. ZEND_PARSE_PARAMETERS_START(1, 1)
  1704. Z_PARAM_ARRAY_HT(data)
  1705. ZEND_PARSE_PARAMETERS_END();
  1706. zval *num = zend_hash_index_find(data, 0);
  1707. if (!num || Z_TYPE_P(num) != IS_STRING ||
  1708. convert_to_gmp(GET_GMP_FROM_ZVAL(ZEND_THIS), num, 16, 0) == FAILURE) {
  1709. zend_throw_exception(NULL, "Could not unserialize number", 0);
  1710. RETURN_THROWS();
  1711. }
  1712. zval *props = zend_hash_index_find(data, 1);
  1713. if (props) {
  1714. if (Z_TYPE_P(props) != IS_ARRAY) {
  1715. zend_throw_exception(NULL, "Could not unserialize properties", 0);
  1716. RETURN_THROWS();
  1717. }
  1718. object_properties_load(Z_OBJ_P(ZEND_THIS), Z_ARRVAL_P(props));
  1719. }
  1720. }