PageRenderTime 50ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/bcmath/bcmath.c

https://bitbucket.org/luobailiang/php-src
C | 579 lines | 410 code | 91 blank | 78 comment | 50 complexity | f47dac90c002435337603062cbe99f5b MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2012 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Andi Gutmans <andi@zend.com> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include "php.h"
  23. #if HAVE_BCMATH
  24. #include "php_ini.h"
  25. #include "ext/standard/info.h"
  26. #include "php_bcmath.h"
  27. #include "libbcmath/src/bcmath.h"
  28. ZEND_DECLARE_MODULE_GLOBALS(bcmath)
  29. static PHP_GINIT_FUNCTION(bcmath);
  30. static PHP_GSHUTDOWN_FUNCTION(bcmath);
  31. /* {{{ arginfo */
  32. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcadd, 0, 0, 2)
  33. ZEND_ARG_INFO(0, left_operand)
  34. ZEND_ARG_INFO(0, right_operand)
  35. ZEND_ARG_INFO(0, scale)
  36. ZEND_END_ARG_INFO()
  37. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsub, 0, 0, 2)
  38. ZEND_ARG_INFO(0, left_operand)
  39. ZEND_ARG_INFO(0, right_operand)
  40. ZEND_ARG_INFO(0, scale)
  41. ZEND_END_ARG_INFO()
  42. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmul, 0, 0, 2)
  43. ZEND_ARG_INFO(0, left_operand)
  44. ZEND_ARG_INFO(0, right_operand)
  45. ZEND_ARG_INFO(0, scale)
  46. ZEND_END_ARG_INFO()
  47. ZEND_BEGIN_ARG_INFO_EX(arginfo_bcdiv, 0, 0, 2)
  48. ZEND_ARG_INFO(0, left_operand)
  49. ZEND_ARG_INFO(0, right_operand)
  50. ZEND_ARG_INFO(0, scale)
  51. ZEND_END_ARG_INFO()
  52. ZEND_BEGIN_ARG_INFO(arginfo_bcmod, 0)
  53. ZEND_ARG_INFO(0, left_operand)
  54. ZEND_ARG_INFO(0, right_operand)
  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(arginfo_bcscale, 0)
  77. ZEND_ARG_INFO(0, scale)
  78. ZEND_END_ARG_INFO()
  79. /* }}} */
  80. 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. NO_VERSION_YET,
  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. ZEND_GET_MODULE(bcmath)
  111. #endif
  112. /* {{{ PHP_INI */
  113. PHP_INI_BEGIN()
  114. STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
  115. PHP_INI_END()
  116. /* }}} */
  117. /* {{{ PHP_GINIT_FUNCTION
  118. */
  119. static PHP_GINIT_FUNCTION(bcmath)
  120. {
  121. bcmath_globals->bc_precision = 0;
  122. bc_init_numbers(TSRMLS_C);
  123. }
  124. /* }}} */
  125. /* {{{ PHP_GSHUTDOWN_FUNCTION
  126. */
  127. static PHP_GSHUTDOWN_FUNCTION(bcmath)
  128. {
  129. _bc_free_num_ex(&bcmath_globals->_zero_, 1);
  130. _bc_free_num_ex(&bcmath_globals->_one_, 1);
  131. _bc_free_num_ex(&bcmath_globals->_two_, 1);
  132. }
  133. /* }}} */
  134. /* {{{ PHP_MINIT_FUNCTION
  135. */
  136. PHP_MINIT_FUNCTION(bcmath)
  137. {
  138. REGISTER_INI_ENTRIES();
  139. return SUCCESS;
  140. }
  141. /* }}} */
  142. /* {{{ PHP_MSHUTDOWN_FUNCTION
  143. */
  144. PHP_MSHUTDOWN_FUNCTION(bcmath)
  145. {
  146. UNREGISTER_INI_ENTRIES();
  147. return SUCCESS;
  148. }
  149. /* }}} */
  150. /* {{{ PHP_MINFO_FUNCTION
  151. */
  152. PHP_MINFO_FUNCTION(bcmath)
  153. {
  154. php_info_print_table_start();
  155. php_info_print_table_row(2, "BCMath support", "enabled");
  156. php_info_print_table_end();
  157. DISPLAY_INI_ENTRIES();
  158. }
  159. /* }}} */
  160. /* {{{ php_str2num
  161. Convert to bc_num detecting scale */
  162. static void php_str2num(bc_num *num, char *str TSRMLS_DC)
  163. {
  164. char *p;
  165. if (!(p = strchr(str, '.'))) {
  166. bc_str2num(num, str, 0 TSRMLS_CC);
  167. return;
  168. }
  169. bc_str2num(num, str, strlen(p+1) TSRMLS_CC);
  170. }
  171. /* }}} */
  172. /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
  173. Returns the sum of two arbitrary precision numbers */
  174. PHP_FUNCTION(bcadd)
  175. {
  176. char *left, *right;
  177. long scale_param = 0;
  178. bc_num first, second, result;
  179. int left_len, right_len;
  180. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  181. if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
  182. return;
  183. }
  184. if (argc == 3) {
  185. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  186. }
  187. bc_init_num(&first TSRMLS_CC);
  188. bc_init_num(&second TSRMLS_CC);
  189. bc_init_num(&result TSRMLS_CC);
  190. php_str2num(&first, left TSRMLS_CC);
  191. php_str2num(&second, right TSRMLS_CC);
  192. bc_add (first, second, &result, scale);
  193. if (result->n_scale > scale) {
  194. result->n_scale = scale;
  195. }
  196. Z_STRVAL_P(return_value) = bc_num2str(result);
  197. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  198. Z_TYPE_P(return_value) = IS_STRING;
  199. bc_free_num(&first);
  200. bc_free_num(&second);
  201. bc_free_num(&result);
  202. return;
  203. }
  204. /* }}} */
  205. /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
  206. Returns the difference between two arbitrary precision numbers */
  207. PHP_FUNCTION(bcsub)
  208. {
  209. char *left, *right;
  210. int left_len, right_len;
  211. long scale_param = 0;
  212. bc_num first, second, result;
  213. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  214. if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
  215. return;
  216. }
  217. if (argc == 3) {
  218. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  219. }
  220. bc_init_num(&first TSRMLS_CC);
  221. bc_init_num(&second TSRMLS_CC);
  222. bc_init_num(&result TSRMLS_CC);
  223. php_str2num(&first, left TSRMLS_CC);
  224. php_str2num(&second, right TSRMLS_CC);
  225. bc_sub (first, second, &result, scale);
  226. if (result->n_scale > scale) {
  227. result->n_scale = scale;
  228. }
  229. Z_STRVAL_P(return_value) = bc_num2str(result);
  230. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  231. Z_TYPE_P(return_value) = IS_STRING;
  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. char *left, *right;
  243. int left_len, right_len;
  244. long scale_param = 0;
  245. bc_num first, second, result;
  246. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  247. if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
  248. return;
  249. }
  250. if (argc == 3) {
  251. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  252. }
  253. bc_init_num(&first TSRMLS_CC);
  254. bc_init_num(&second TSRMLS_CC);
  255. bc_init_num(&result TSRMLS_CC);
  256. php_str2num(&first, left TSRMLS_CC);
  257. php_str2num(&second, right TSRMLS_CC);
  258. bc_multiply (first, second, &result, scale TSRMLS_CC);
  259. if (result->n_scale > scale) {
  260. result->n_scale = scale;
  261. }
  262. Z_STRVAL_P(return_value) = bc_num2str(result);
  263. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  264. Z_TYPE_P(return_value) = IS_STRING;
  265. bc_free_num(&first);
  266. bc_free_num(&second);
  267. bc_free_num(&result);
  268. return;
  269. }
  270. /* }}} */
  271. /* {{{ proto string bcdiv(string left_operand, string right_operand [, int scale])
  272. Returns the quotient of two arbitrary precision numbers (division) */
  273. PHP_FUNCTION(bcdiv)
  274. {
  275. char *left, *right;
  276. int left_len, right_len;
  277. long scale_param = 0;
  278. bc_num first, second, result;
  279. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  280. if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
  281. return;
  282. }
  283. if (argc == 3) {
  284. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  285. }
  286. bc_init_num(&first TSRMLS_CC);
  287. bc_init_num(&second TSRMLS_CC);
  288. bc_init_num(&result TSRMLS_CC);
  289. php_str2num(&first, left TSRMLS_CC);
  290. php_str2num(&second, right TSRMLS_CC);
  291. switch (bc_divide(first, second, &result, scale TSRMLS_CC)) {
  292. case 0: /* OK */
  293. if (result->n_scale > scale) {
  294. result->n_scale = scale;
  295. }
  296. Z_STRVAL_P(return_value) = bc_num2str(result);
  297. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  298. Z_TYPE_P(return_value) = IS_STRING;
  299. break;
  300. case -1: /* division by zero */
  301. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
  302. break;
  303. }
  304. bc_free_num(&first);
  305. bc_free_num(&second);
  306. bc_free_num(&result);
  307. return;
  308. }
  309. /* }}} */
  310. /* {{{ proto string bcmod(string left_operand, string right_operand)
  311. Returns the modulus of the two arbitrary precision operands */
  312. PHP_FUNCTION(bcmod)
  313. {
  314. char *left, *right;
  315. int left_len, right_len;
  316. bc_num first, second, result;
  317. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &left, &left_len, &right, &right_len) == FAILURE) {
  318. return;
  319. }
  320. bc_init_num(&first TSRMLS_CC);
  321. bc_init_num(&second TSRMLS_CC);
  322. bc_init_num(&result TSRMLS_CC);
  323. bc_str2num(&first, left, 0 TSRMLS_CC);
  324. bc_str2num(&second, right, 0 TSRMLS_CC);
  325. switch (bc_modulo(first, second, &result, 0 TSRMLS_CC)) {
  326. case 0:
  327. Z_STRVAL_P(return_value) = bc_num2str(result);
  328. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  329. Z_TYPE_P(return_value) = IS_STRING;
  330. break;
  331. case -1:
  332. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
  333. break;
  334. }
  335. bc_free_num(&first);
  336. bc_free_num(&second);
  337. bc_free_num(&result);
  338. return;
  339. }
  340. /* }}} */
  341. /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
  342. Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
  343. PHP_FUNCTION(bcpowmod)
  344. {
  345. char *left, *right, *modulous;
  346. int left_len, right_len, modulous_len;
  347. bc_num first, second, mod, result;
  348. long scale = BCG(bc_precision);
  349. int scale_int;
  350. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &left, &left_len, &right, &right_len, &modulous, &modulous_len, &scale) == FAILURE) {
  351. return;
  352. }
  353. bc_init_num(&first TSRMLS_CC);
  354. bc_init_num(&second TSRMLS_CC);
  355. bc_init_num(&mod TSRMLS_CC);
  356. bc_init_num(&result TSRMLS_CC);
  357. php_str2num(&first, left TSRMLS_CC);
  358. php_str2num(&second, right TSRMLS_CC);
  359. php_str2num(&mod, modulous TSRMLS_CC);
  360. scale_int = (int) ((int)scale < 0) ? 0 : scale;
  361. if (bc_raisemod(first, second, mod, &result, scale_int TSRMLS_CC) != -1) {
  362. if (result->n_scale > scale) {
  363. result->n_scale = scale;
  364. }
  365. Z_STRVAL_P(return_value) = bc_num2str(result);
  366. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  367. Z_TYPE_P(return_value) = IS_STRING;
  368. } else {
  369. RETVAL_FALSE;
  370. }
  371. bc_free_num(&first);
  372. bc_free_num(&second);
  373. bc_free_num(&mod);
  374. bc_free_num(&result);
  375. return;
  376. }
  377. /* }}} */
  378. /* {{{ proto string bcpow(string x, string y [, int scale])
  379. Returns the value of an arbitrary precision number raised to the power of another */
  380. PHP_FUNCTION(bcpow)
  381. {
  382. char *left, *right;
  383. int left_len, right_len;
  384. long scale_param = 0;
  385. bc_num first, second, result;
  386. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  387. if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
  388. return;
  389. }
  390. if (argc == 3) {
  391. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  392. }
  393. bc_init_num(&first TSRMLS_CC);
  394. bc_init_num(&second TSRMLS_CC);
  395. bc_init_num(&result TSRMLS_CC);
  396. php_str2num(&first, left TSRMLS_CC);
  397. php_str2num(&second, right TSRMLS_CC);
  398. bc_raise (first, second, &result, scale TSRMLS_CC);
  399. if (result->n_scale > scale) {
  400. result->n_scale = scale;
  401. }
  402. Z_STRVAL_P(return_value) = bc_num2str(result);
  403. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  404. Z_TYPE_P(return_value) = IS_STRING;
  405. bc_free_num(&first);
  406. bc_free_num(&second);
  407. bc_free_num(&result);
  408. return;
  409. }
  410. /* }}} */
  411. /* {{{ proto string bcsqrt(string operand [, int scale])
  412. Returns the square root of an arbitray precision number */
  413. PHP_FUNCTION(bcsqrt)
  414. {
  415. char *left;
  416. int left_len;
  417. long scale_param = 0;
  418. bc_num result;
  419. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  420. if (zend_parse_parameters(argc TSRMLS_CC, "s|l", &left, &left_len, &scale_param) == FAILURE) {
  421. return;
  422. }
  423. if (argc == 2) {
  424. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  425. }
  426. bc_init_num(&result TSRMLS_CC);
  427. php_str2num(&result, left TSRMLS_CC);
  428. if (bc_sqrt (&result, scale TSRMLS_CC) != 0) {
  429. if (result->n_scale > scale) {
  430. result->n_scale = scale;
  431. }
  432. Z_STRVAL_P(return_value) = bc_num2str(result);
  433. Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
  434. Z_TYPE_P(return_value) = IS_STRING;
  435. } else {
  436. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Square root of negative number");
  437. }
  438. bc_free_num(&result);
  439. return;
  440. }
  441. /* }}} */
  442. /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
  443. Compares two arbitrary precision numbers */
  444. PHP_FUNCTION(bccomp)
  445. {
  446. char *left, *right;
  447. int left_len, right_len;
  448. long scale_param = 0;
  449. bc_num first, second;
  450. int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
  451. if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
  452. return;
  453. }
  454. if (argc == 3) {
  455. scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
  456. }
  457. bc_init_num(&first TSRMLS_CC);
  458. bc_init_num(&second TSRMLS_CC);
  459. bc_str2num(&first, left, scale TSRMLS_CC);
  460. bc_str2num(&second, right, scale TSRMLS_CC);
  461. Z_LVAL_P(return_value) = bc_compare(first, second);
  462. Z_TYPE_P(return_value) = IS_LONG;
  463. bc_free_num(&first);
  464. bc_free_num(&second);
  465. return;
  466. }
  467. /* }}} */
  468. /* {{{ proto bool bcscale(int scale)
  469. Sets default scale parameter for all bc math functions */
  470. PHP_FUNCTION(bcscale)
  471. {
  472. long new_scale;
  473. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_scale) == FAILURE) {
  474. return;
  475. }
  476. BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
  477. RETURN_TRUE;
  478. }
  479. /* }}} */
  480. #endif
  481. /*
  482. * Local variables:
  483. * tab-width: 4
  484. * c-basic-offset: 4
  485. * End:
  486. * vim600: sw=4 ts=4 fdm=marker
  487. * vim<600: sw=4 ts=4
  488. */