gmp.c 56 KB

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