bcmath.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  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: Andi Gutmans <andi@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include "config.h"
  20. #endif
  21. #include "php.h"
  22. #if HAVE_BCMATH
  23. #include "php_ini.h"
  24. #include "ext/standard/info.h"
  25. #include "php_bcmath.h"
  26. #include "libbcmath/src/bcmath.h"
  27. ZEND_DECLARE_MODULE_GLOBALS(bcmath)
  28. static PHP_GINIT_FUNCTION(bcmath);
  29. static PHP_GSHUTDOWN_FUNCTION(bcmath);
  30. /* {{{ arginfo */
  31. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcadd, 0, 0, 2)
  32. ZEND_ARG_INFO(0, left_operand)
  33. ZEND_ARG_INFO(0, right_operand)
  34. ZEND_ARG_INFO(0, scale)
  35. ZEND_END_ARG_INFO()
  36. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsub, 0, 0, 2)
  37. ZEND_ARG_INFO(0, left_operand)
  38. ZEND_ARG_INFO(0, right_operand)
  39. ZEND_ARG_INFO(0, scale)
  40. ZEND_END_ARG_INFO()
  41. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmul, 0, 0, 2)
  42. ZEND_ARG_INFO(0, left_operand)
  43. ZEND_ARG_INFO(0, right_operand)
  44. ZEND_ARG_INFO(0, scale)
  45. ZEND_END_ARG_INFO()
  46. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcdiv, 0, 0, 2)
  47. ZEND_ARG_INFO(0, left_operand)
  48. ZEND_ARG_INFO(0, right_operand)
  49. ZEND_ARG_INFO(0, scale)
  50. ZEND_END_ARG_INFO()
  51. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmod, 0, 0, 2)
  52. ZEND_ARG_INFO(0, left_operand)
  53. ZEND_ARG_INFO(0, right_operand)
  54. ZEND_ARG_INFO(0, scale)
  55. ZEND_END_ARG_INFO()
  56. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpowmod, 0, 0, 3)
  57. ZEND_ARG_INFO(0, x)
  58. ZEND_ARG_INFO(0, y)
  59. ZEND_ARG_INFO(0, mod)
  60. ZEND_ARG_INFO(0, scale)
  61. ZEND_END_ARG_INFO()
  62. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpow, 0, 0, 2)
  63. ZEND_ARG_INFO(0, x)
  64. ZEND_ARG_INFO(0, y)
  65. ZEND_ARG_INFO(0, scale)
  66. ZEND_END_ARG_INFO()
  67. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsqrt, 0, 0, 1)
  68. ZEND_ARG_INFO(0, operand)
  69. ZEND_ARG_INFO(0, scale)
  70. ZEND_END_ARG_INFO()
  71. ZEND_BEGIN_ARG_INFO_EX(arginfo_bccomp, 0, 0, 2)
  72. ZEND_ARG_INFO(0, left_operand)
  73. ZEND_ARG_INFO(0, right_operand)
  74. ZEND_ARG_INFO(0, scale)
  75. ZEND_END_ARG_INFO()
  76. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcscale, 0, 0, 0)
  77. ZEND_ARG_INFO(0, scale)
  78. ZEND_END_ARG_INFO()
  79. /* }}} */
  80. static const zend_function_entry bcmath_functions[] = {
  81. PHP_FE(bcadd, arginfo_bcadd)
  82. PHP_FE(bcsub, arginfo_bcsub)
  83. PHP_FE(bcmul, arginfo_bcmul)
  84. PHP_FE(bcdiv, arginfo_bcdiv)
  85. PHP_FE(bcmod, arginfo_bcmod)
  86. PHP_FE(bcpow, arginfo_bcpow)
  87. PHP_FE(bcsqrt, arginfo_bcsqrt)
  88. PHP_FE(bcscale, arginfo_bcscale)
  89. PHP_FE(bccomp, arginfo_bccomp)
  90. PHP_FE(bcpowmod, arginfo_bcpowmod)
  91. PHP_FE_END
  92. };
  93. zend_module_entry bcmath_module_entry = {
  94. STANDARD_MODULE_HEADER,
  95. "bcmath",
  96. bcmath_functions,
  97. PHP_MINIT(bcmath),
  98. PHP_MSHUTDOWN(bcmath),
  99. NULL,
  100. NULL,
  101. PHP_MINFO(bcmath),
  102. PHP_BCMATH_VERSION,
  103. PHP_MODULE_GLOBALS(bcmath),
  104. PHP_GINIT(bcmath),
  105. PHP_GSHUTDOWN(bcmath),
  106. NULL,
  107. STANDARD_MODULE_PROPERTIES_EX
  108. };
  109. #ifdef COMPILE_DL_BCMATH
  110. #ifdef ZTS
  111. ZEND_TSRMLS_CACHE_DEFINE()
  112. #endif
  113. ZEND_GET_MODULE(bcmath)
  114. #endif
  115. /* {{{ PHP_INI */
  116. PHP_INI_BEGIN()
  117. STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
  118. PHP_INI_END()
  119. /* }}} */
  120. /* {{{ PHP_GINIT_FUNCTION
  121. */
  122. static PHP_GINIT_FUNCTION(bcmath)
  123. {
  124. #if defined(COMPILE_DL_BCMATH) && defined(ZTS)
  125. ZEND_TSRMLS_CACHE_UPDATE();
  126. #endif
  127. bcmath_globals->bc_precision = 0;
  128. bc_init_numbers();
  129. }
  130. /* }}} */
  131. /* {{{ PHP_GSHUTDOWN_FUNCTION
  132. */
  133. static PHP_GSHUTDOWN_FUNCTION(bcmath)
  134. {
  135. _bc_free_num_ex(&bcmath_globals->_zero_, 1);
  136. _bc_free_num_ex(&bcmath_globals->_one_, 1);
  137. _bc_free_num_ex(&bcmath_globals->_two_, 1);
  138. }
  139. /* }}} */
  140. /* {{{ PHP_MINIT_FUNCTION
  141. */
  142. PHP_MINIT_FUNCTION(bcmath)
  143. {
  144. REGISTER_INI_ENTRIES();
  145. return SUCCESS;
  146. }
  147. /* }}} */
  148. /* {{{ PHP_MSHUTDOWN_FUNCTION
  149. */
  150. PHP_MSHUTDOWN_FUNCTION(bcmath)
  151. {
  152. UNREGISTER_INI_ENTRIES();
  153. return SUCCESS;
  154. }
  155. /* }}} */
  156. /* {{{ PHP_MINFO_FUNCTION
  157. */
  158. PHP_MINFO_FUNCTION(bcmath)
  159. {
  160. php_info_print_table_start();
  161. php_info_print_table_row(2, "BCMath support", "enabled");
  162. php_info_print_table_end();
  163. DISPLAY_INI_ENTRIES();
  164. }
  165. /* }}} */
  166. /* {{{ php_str2num
  167. Convert to bc_num detecting scale */
  168. static void php_str2num(bc_num *num, char *str)
  169. {
  170. char *p;
  171. if (!(p = strchr(str, '.'))) {
  172. bc_str2num(num, str, 0);
  173. return;
  174. }
  175. bc_str2num(num, str, strlen(p+1));
  176. }
  177. /* }}} */
  178. /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
  179. Returns the sum of two arbitrary precision numbers */
  180. PHP_FUNCTION(bcadd)
  181. {
  182. zend_string *left, *right;
  183. zend_long scale_param = 0;
  184. bc_num first, second, result;
  185. int scale = (int)BCG(bc_precision);
  186. ZEND_PARSE_PARAMETERS_START(2, 3)
  187. Z_PARAM_STR(left)
  188. Z_PARAM_STR(right)
  189. Z_PARAM_OPTIONAL
  190. Z_PARAM_LONG(scale_param)
  191. ZEND_PARSE_PARAMETERS_END();
  192. if (ZEND_NUM_ARGS() == 3) {
  193. scale = (int) (scale_param < 0 ? 0 : scale_param);
  194. }
  195. bc_init_num(&first);
  196. bc_init_num(&second);
  197. bc_init_num(&result);
  198. php_str2num(&first, ZSTR_VAL(left));
  199. php_str2num(&second, ZSTR_VAL(right));
  200. bc_add (first, second, &result, scale);
  201. RETVAL_STR(bc_num2str_ex(result, scale));
  202. bc_free_num(&first);
  203. bc_free_num(&second);
  204. bc_free_num(&result);
  205. return;
  206. }
  207. /* }}} */
  208. /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
  209. Returns the difference between two arbitrary precision numbers */
  210. PHP_FUNCTION(bcsub)
  211. {
  212. zend_string *left, *right;
  213. zend_long scale_param = 0;
  214. bc_num first, second, result;
  215. int scale = (int)BCG(bc_precision);
  216. ZEND_PARSE_PARAMETERS_START(2, 3)
  217. Z_PARAM_STR(left)
  218. Z_PARAM_STR(right)
  219. Z_PARAM_OPTIONAL
  220. Z_PARAM_LONG(scale_param)
  221. ZEND_PARSE_PARAMETERS_END();
  222. if (ZEND_NUM_ARGS() == 3) {
  223. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  224. }
  225. bc_init_num(&first);
  226. bc_init_num(&second);
  227. bc_init_num(&result);
  228. php_str2num(&first, ZSTR_VAL(left));
  229. php_str2num(&second, ZSTR_VAL(right));
  230. bc_sub (first, second, &result, scale);
  231. RETVAL_STR(bc_num2str_ex(result, scale));
  232. bc_free_num(&first);
  233. bc_free_num(&second);
  234. bc_free_num(&result);
  235. return;
  236. }
  237. /* }}} */
  238. /* {{{ proto string bcmul(string left_operand, string right_operand [, int scale])
  239. Returns the multiplication of two arbitrary precision numbers */
  240. PHP_FUNCTION(bcmul)
  241. {
  242. zend_string *left, *right;
  243. zend_long scale_param = 0;
  244. bc_num first, second, result;
  245. int scale = (int)BCG(bc_precision);
  246. ZEND_PARSE_PARAMETERS_START(2, 3)
  247. Z_PARAM_STR(left)
  248. Z_PARAM_STR(right)
  249. Z_PARAM_OPTIONAL
  250. Z_PARAM_LONG(scale_param)
  251. ZEND_PARSE_PARAMETERS_END();
  252. if (ZEND_NUM_ARGS() == 3) {
  253. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  254. }
  255. bc_init_num(&first);
  256. bc_init_num(&second);
  257. bc_init_num(&result);
  258. php_str2num(&first, ZSTR_VAL(left));
  259. php_str2num(&second, ZSTR_VAL(right));
  260. bc_multiply (first, second, &result, scale);
  261. RETVAL_STR(bc_num2str_ex(result, scale));
  262. bc_free_num(&first);
  263. bc_free_num(&second);
  264. bc_free_num(&result);
  265. return;
  266. }
  267. /* }}} */
  268. /* {{{ proto string bcdiv(string left_operand, string right_operand [, int scale])
  269. Returns the quotient of two arbitrary precision numbers (division) */
  270. PHP_FUNCTION(bcdiv)
  271. {
  272. zend_string *left, *right;
  273. zend_long scale_param = 0;
  274. bc_num first, second, result;
  275. int scale = (int)BCG(bc_precision);
  276. ZEND_PARSE_PARAMETERS_START(2, 3)
  277. Z_PARAM_STR(left)
  278. Z_PARAM_STR(right)
  279. Z_PARAM_OPTIONAL
  280. Z_PARAM_LONG(scale_param)
  281. ZEND_PARSE_PARAMETERS_END();
  282. if (ZEND_NUM_ARGS() == 3) {
  283. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  284. }
  285. bc_init_num(&first);
  286. bc_init_num(&second);
  287. bc_init_num(&result);
  288. php_str2num(&first, ZSTR_VAL(left));
  289. php_str2num(&second, ZSTR_VAL(right));
  290. switch (bc_divide(first, second, &result, scale)) {
  291. case 0: /* OK */
  292. RETVAL_STR(bc_num2str_ex(result, scale));
  293. break;
  294. case -1: /* division by zero */
  295. php_error_docref(NULL, E_WARNING, "Division by zero");
  296. break;
  297. }
  298. bc_free_num(&first);
  299. bc_free_num(&second);
  300. bc_free_num(&result);
  301. return;
  302. }
  303. /* }}} */
  304. /* {{{ proto string bcmod(string left_operand, string right_operand [, int scale])
  305. Returns the modulus of the two arbitrary precision operands */
  306. PHP_FUNCTION(bcmod)
  307. {
  308. zend_string *left, *right;
  309. zend_long scale_param = 0;
  310. bc_num first, second, result;
  311. int scale = (int)BCG(bc_precision);
  312. ZEND_PARSE_PARAMETERS_START(2, 3)
  313. Z_PARAM_STR(left)
  314. Z_PARAM_STR(right)
  315. Z_PARAM_OPTIONAL
  316. Z_PARAM_LONG(scale_param)
  317. ZEND_PARSE_PARAMETERS_END();
  318. if (ZEND_NUM_ARGS() == 3) {
  319. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  320. }
  321. bc_init_num(&first);
  322. bc_init_num(&second);
  323. bc_init_num(&result);
  324. php_str2num(&first, ZSTR_VAL(left));
  325. php_str2num(&second, ZSTR_VAL(right));
  326. switch (bc_modulo(first, second, &result, scale)) {
  327. case 0:
  328. RETVAL_STR(bc_num2str_ex(result, scale));
  329. break;
  330. case -1:
  331. php_error_docref(NULL, E_WARNING, "Division by zero");
  332. break;
  333. }
  334. bc_free_num(&first);
  335. bc_free_num(&second);
  336. bc_free_num(&result);
  337. return;
  338. }
  339. /* }}} */
  340. /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
  341. Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
  342. PHP_FUNCTION(bcpowmod)
  343. {
  344. zend_string *left, *right, *modulous;
  345. bc_num first, second, mod, result;
  346. zend_long scale = BCG(bc_precision);
  347. int scale_int;
  348. ZEND_PARSE_PARAMETERS_START(3, 4)
  349. Z_PARAM_STR(left)
  350. Z_PARAM_STR(right)
  351. Z_PARAM_STR(modulous)
  352. Z_PARAM_OPTIONAL
  353. Z_PARAM_LONG(scale)
  354. ZEND_PARSE_PARAMETERS_END();
  355. bc_init_num(&first);
  356. bc_init_num(&second);
  357. bc_init_num(&mod);
  358. bc_init_num(&result);
  359. php_str2num(&first, ZSTR_VAL(left));
  360. php_str2num(&second, ZSTR_VAL(right));
  361. php_str2num(&mod, ZSTR_VAL(modulous));
  362. scale_int = (int) ((int)scale < 0 ? 0 : scale);
  363. if (bc_raisemod(first, second, mod, &result, scale_int) != -1) {
  364. RETVAL_STR(bc_num2str_ex(result, scale_int));
  365. } else {
  366. RETVAL_FALSE;
  367. }
  368. bc_free_num(&first);
  369. bc_free_num(&second);
  370. bc_free_num(&mod);
  371. bc_free_num(&result);
  372. return;
  373. }
  374. /* }}} */
  375. /* {{{ proto string bcpow(string x, string y [, int scale])
  376. Returns the value of an arbitrary precision number raised to the power of another */
  377. PHP_FUNCTION(bcpow)
  378. {
  379. zend_string *left, *right;
  380. zend_long scale_param = 0;
  381. bc_num first, second, result;
  382. int scale = (int)BCG(bc_precision);
  383. ZEND_PARSE_PARAMETERS_START(2, 3)
  384. Z_PARAM_STR(left)
  385. Z_PARAM_STR(right)
  386. Z_PARAM_OPTIONAL
  387. Z_PARAM_LONG(scale_param)
  388. ZEND_PARSE_PARAMETERS_END();
  389. if (ZEND_NUM_ARGS() == 3) {
  390. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  391. }
  392. bc_init_num(&first);
  393. bc_init_num(&second);
  394. bc_init_num(&result);
  395. php_str2num(&first, ZSTR_VAL(left));
  396. php_str2num(&second, ZSTR_VAL(right));
  397. bc_raise (first, second, &result, scale);
  398. RETVAL_STR(bc_num2str_ex(result, scale));
  399. bc_free_num(&first);
  400. bc_free_num(&second);
  401. bc_free_num(&result);
  402. return;
  403. }
  404. /* }}} */
  405. /* {{{ proto string bcsqrt(string operand [, int scale])
  406. Returns the square root of an arbitray precision number */
  407. PHP_FUNCTION(bcsqrt)
  408. {
  409. zend_string *left;
  410. zend_long scale_param = 0;
  411. bc_num result;
  412. int scale = (int)BCG(bc_precision);
  413. ZEND_PARSE_PARAMETERS_START(1, 2)
  414. Z_PARAM_STR(left)
  415. Z_PARAM_OPTIONAL
  416. Z_PARAM_LONG(scale_param)
  417. ZEND_PARSE_PARAMETERS_END();
  418. if (ZEND_NUM_ARGS() == 2) {
  419. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  420. }
  421. bc_init_num(&result);
  422. php_str2num(&result, ZSTR_VAL(left));
  423. if (bc_sqrt (&result, scale) != 0) {
  424. RETVAL_STR(bc_num2str_ex(result, scale));
  425. } else {
  426. php_error_docref(NULL, E_WARNING, "Square root of negative number");
  427. }
  428. bc_free_num(&result);
  429. return;
  430. }
  431. /* }}} */
  432. /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
  433. Compares two arbitrary precision numbers */
  434. PHP_FUNCTION(bccomp)
  435. {
  436. zend_string *left, *right;
  437. zend_long scale_param = 0;
  438. bc_num first, second;
  439. int scale = (int)BCG(bc_precision);
  440. ZEND_PARSE_PARAMETERS_START(2, 3)
  441. Z_PARAM_STR(left)
  442. Z_PARAM_STR(right)
  443. Z_PARAM_OPTIONAL
  444. Z_PARAM_LONG(scale_param)
  445. ZEND_PARSE_PARAMETERS_END();
  446. if (ZEND_NUM_ARGS() == 3) {
  447. scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
  448. }
  449. bc_init_num(&first);
  450. bc_init_num(&second);
  451. bc_str2num(&first, ZSTR_VAL(left), scale);
  452. bc_str2num(&second, ZSTR_VAL(right), scale);
  453. RETVAL_LONG(bc_compare(first, second));
  454. bc_free_num(&first);
  455. bc_free_num(&second);
  456. return;
  457. }
  458. /* }}} */
  459. /* {{{ proto int bcscale([int scale])
  460. Sets default scale parameter for all bc math functions */
  461. PHP_FUNCTION(bcscale)
  462. {
  463. zend_long old_scale, new_scale;
  464. ZEND_PARSE_PARAMETERS_START(0, 1)
  465. Z_PARAM_OPTIONAL
  466. Z_PARAM_LONG(new_scale)
  467. ZEND_PARSE_PARAMETERS_END();
  468. old_scale = BCG(bc_precision);
  469. if (ZEND_NUM_ARGS() == 1) {
  470. BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
  471. }
  472. RETURN_LONG(old_scale);
  473. }
  474. /* }}} */
  475. #endif
  476. /*
  477. * Local variables:
  478. * tab-width: 4
  479. * c-basic-offset: 4
  480. * End:
  481. * vim600: sw=4 ts=4 fdm=marker
  482. * vim<600: sw=4 ts=4
  483. */