Back to index

php5  5.3.10
bcmath.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Author: Andi Gutmans <andi@zend.com>                                 |
00016    +----------------------------------------------------------------------+
00017 */
00018 
00019 /* $Id: bcmath.c 321634 2012-01-01 13:15:04Z felipe $ */
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024 
00025 #include "php.h"
00026 
00027 #if HAVE_BCMATH
00028 
00029 #include "php_ini.h"
00030 #include "ext/standard/info.h"
00031 #include "php_bcmath.h"
00032 #include "libbcmath/src/bcmath.h"
00033 
00034 ZEND_DECLARE_MODULE_GLOBALS(bcmath)
00035 static PHP_GINIT_FUNCTION(bcmath);
00036 static PHP_GSHUTDOWN_FUNCTION(bcmath);
00037 
00038 /* {{{ arginfo */
00039 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcadd, 0, 0, 2)
00040        ZEND_ARG_INFO(0, left_operand)
00041        ZEND_ARG_INFO(0, right_operand)
00042        ZEND_ARG_INFO(0, scale)
00043 ZEND_END_ARG_INFO()
00044 
00045 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsub, 0, 0, 2)
00046        ZEND_ARG_INFO(0, left_operand)
00047        ZEND_ARG_INFO(0, right_operand)
00048        ZEND_ARG_INFO(0, scale)
00049 ZEND_END_ARG_INFO()
00050 
00051 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmul, 0, 0, 2)
00052        ZEND_ARG_INFO(0, left_operand)
00053        ZEND_ARG_INFO(0, right_operand)
00054        ZEND_ARG_INFO(0, scale)
00055 ZEND_END_ARG_INFO()
00056 
00057 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcdiv, 0, 0, 2)
00058        ZEND_ARG_INFO(0, left_operand)
00059        ZEND_ARG_INFO(0, right_operand)
00060        ZEND_ARG_INFO(0, scale)
00061 ZEND_END_ARG_INFO()
00062 
00063 ZEND_BEGIN_ARG_INFO(arginfo_bcmod, 0)
00064        ZEND_ARG_INFO(0, left_operand)
00065        ZEND_ARG_INFO(0, right_operand)
00066 ZEND_END_ARG_INFO()
00067 
00068 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpowmod, 0, 0, 3)
00069        ZEND_ARG_INFO(0, x)
00070        ZEND_ARG_INFO(0, y)
00071        ZEND_ARG_INFO(0, mod)
00072        ZEND_ARG_INFO(0, scale)
00073 ZEND_END_ARG_INFO()
00074 
00075 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpow, 0, 0, 2)
00076        ZEND_ARG_INFO(0, x)
00077        ZEND_ARG_INFO(0, y)
00078        ZEND_ARG_INFO(0, scale)
00079 ZEND_END_ARG_INFO()
00080 
00081 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsqrt, 0, 0, 1)
00082        ZEND_ARG_INFO(0, operand)
00083        ZEND_ARG_INFO(0, scale)
00084 ZEND_END_ARG_INFO()
00085 
00086 ZEND_BEGIN_ARG_INFO_EX(arginfo_bccomp, 0, 0, 2)
00087        ZEND_ARG_INFO(0, left_operand)
00088        ZEND_ARG_INFO(0, right_operand)
00089        ZEND_ARG_INFO(0, scale)
00090 ZEND_END_ARG_INFO()
00091 
00092 ZEND_BEGIN_ARG_INFO(arginfo_bcscale, 0)
00093        ZEND_ARG_INFO(0, scale)
00094 ZEND_END_ARG_INFO()
00095 
00096 /* }}} */
00097 
00098 const zend_function_entry bcmath_functions[] = {
00099        PHP_FE(bcadd,                                                         arginfo_bcadd)
00100        PHP_FE(bcsub,                                                         arginfo_bcsub)
00101        PHP_FE(bcmul,                                                         arginfo_bcmul)
00102        PHP_FE(bcdiv,                                                         arginfo_bcdiv)
00103        PHP_FE(bcmod,                                                         arginfo_bcmod)
00104        PHP_FE(bcpow,                                                         arginfo_bcpow)
00105        PHP_FE(bcsqrt,                                                               arginfo_bcsqrt)
00106        PHP_FE(bcscale,                                                              arginfo_bcscale)
00107        PHP_FE(bccomp,                                                               arginfo_bccomp)
00108        PHP_FE(bcpowmod,                                                      arginfo_bcpowmod)
00109        PHP_FE_END
00110 };
00111 
00112 zend_module_entry bcmath_module_entry = {
00113        STANDARD_MODULE_HEADER,
00114        "bcmath",
00115        bcmath_functions,
00116        PHP_MINIT(bcmath),
00117        PHP_MSHUTDOWN(bcmath),
00118        NULL,
00119        NULL,
00120        PHP_MINFO(bcmath),
00121        NO_VERSION_YET,
00122        PHP_MODULE_GLOBALS(bcmath),
00123        PHP_GINIT(bcmath),
00124     PHP_GSHUTDOWN(bcmath),
00125        NULL,
00126        STANDARD_MODULE_PROPERTIES_EX
00127 };
00128 
00129 #ifdef COMPILE_DL_BCMATH
00130 ZEND_GET_MODULE(bcmath)
00131 #endif
00132 
00133 /* {{{ PHP_INI */
00134 PHP_INI_BEGIN()
00135        STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
00136 PHP_INI_END()
00137 /* }}} */
00138 
00139 /* {{{ PHP_GINIT_FUNCTION
00140  */
00141 static PHP_GINIT_FUNCTION(bcmath)
00142 {
00143        bcmath_globals->bc_precision = 0;
00144        bc_init_numbers(TSRMLS_C);
00145 }
00146 /* }}} */
00147 
00148 /* {{{ PHP_GSHUTDOWN_FUNCTION
00149  */
00150 static PHP_GSHUTDOWN_FUNCTION(bcmath)
00151 {
00152        _bc_free_num_ex(&bcmath_globals->_zero_, 1);
00153        _bc_free_num_ex(&bcmath_globals->_one_, 1);
00154        _bc_free_num_ex(&bcmath_globals->_two_, 1);
00155 }
00156 /* }}} */
00157 
00158 /* {{{ PHP_MINIT_FUNCTION
00159  */
00160 PHP_MINIT_FUNCTION(bcmath)
00161 {
00162        REGISTER_INI_ENTRIES();
00163 
00164        return SUCCESS;
00165 }
00166 /* }}} */
00167 
00168 /* {{{ PHP_MSHUTDOWN_FUNCTION
00169  */
00170 PHP_MSHUTDOWN_FUNCTION(bcmath)
00171 {
00172        UNREGISTER_INI_ENTRIES();
00173 
00174        return SUCCESS;
00175 }
00176 /* }}} */
00177 
00178 /* {{{ PHP_MINFO_FUNCTION
00179  */
00180 PHP_MINFO_FUNCTION(bcmath)
00181 {
00182        php_info_print_table_start();
00183        php_info_print_table_row(2, "BCMath support", "enabled");
00184        php_info_print_table_end();
00185        DISPLAY_INI_ENTRIES();
00186 }
00187 /* }}} */
00188 
00189 /* {{{ php_str2num
00190    Convert to bc_num detecting scale */
00191 static void php_str2num(bc_num *num, char *str TSRMLS_DC)
00192 {
00193        char *p;
00194 
00195        if (!(p = strchr(str, '.'))) {
00196               bc_str2num(num, str, 0 TSRMLS_CC);
00197               return;
00198        }
00199 
00200        bc_str2num(num, str, strlen(p+1) TSRMLS_CC);
00201 }
00202 /* }}} */
00203 
00204 /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
00205    Returns the sum of two arbitrary precision numbers */
00206 PHP_FUNCTION(bcadd)
00207 {
00208        char *left, *right;
00209        long scale_param = 0;
00210        bc_num first, second, result;
00211        int left_len, right_len;
00212        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00213 
00214        if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
00215               return;
00216        }
00217        
00218        if (argc == 3) {
00219               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00220        }
00221 
00222        bc_init_num(&first TSRMLS_CC);
00223        bc_init_num(&second TSRMLS_CC);
00224        bc_init_num(&result TSRMLS_CC);
00225        php_str2num(&first, left TSRMLS_CC);
00226        php_str2num(&second, right TSRMLS_CC);
00227        bc_add (first, second, &result, scale);
00228        
00229        if (result->n_scale > scale) {
00230               result->n_scale = scale;
00231        }
00232        
00233        Z_STRVAL_P(return_value) = bc_num2str(result);
00234        Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00235        Z_TYPE_P(return_value) = IS_STRING;
00236        bc_free_num(&first);
00237        bc_free_num(&second);
00238        bc_free_num(&result);
00239        return;
00240 }
00241 /* }}} */
00242 
00243 /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
00244    Returns the difference between two arbitrary precision numbers */
00245 PHP_FUNCTION(bcsub)
00246 {
00247        char *left, *right;
00248        int left_len, right_len;
00249        long scale_param = 0;
00250        bc_num first, second, result;
00251        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00252 
00253        if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
00254               return;
00255        }
00256        
00257        if (argc == 3) {
00258               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00259        }
00260 
00261        bc_init_num(&first TSRMLS_CC);
00262        bc_init_num(&second TSRMLS_CC);
00263        bc_init_num(&result TSRMLS_CC);
00264        php_str2num(&first, left TSRMLS_CC);
00265        php_str2num(&second, right TSRMLS_CC);
00266        bc_sub (first, second, &result, scale);
00267 
00268        if (result->n_scale > scale) {
00269               result->n_scale = scale;
00270        }
00271 
00272        Z_STRVAL_P(return_value) = bc_num2str(result);
00273        Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00274        Z_TYPE_P(return_value) = IS_STRING;
00275        bc_free_num(&first);
00276        bc_free_num(&second);
00277        bc_free_num(&result);
00278        return;
00279 }
00280 /* }}} */
00281 
00282 /* {{{ proto string bcmul(string left_operand, string right_operand [, int scale])
00283    Returns the multiplication of two arbitrary precision numbers */
00284 PHP_FUNCTION(bcmul)
00285 {
00286        char *left, *right;
00287        int left_len, right_len;
00288        long scale_param = 0;
00289        bc_num first, second, result;
00290        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00291 
00292        if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
00293               return;
00294        }
00295        
00296        if (argc == 3) {
00297               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00298        }
00299        
00300        bc_init_num(&first TSRMLS_CC);
00301        bc_init_num(&second TSRMLS_CC);
00302        bc_init_num(&result TSRMLS_CC);
00303        php_str2num(&first, left TSRMLS_CC);
00304        php_str2num(&second, right TSRMLS_CC);
00305        bc_multiply (first, second, &result, scale TSRMLS_CC);
00306 
00307        if (result->n_scale > scale) {
00308               result->n_scale = scale;
00309        }
00310 
00311        Z_STRVAL_P(return_value) = bc_num2str(result);
00312        Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00313        Z_TYPE_P(return_value) = IS_STRING;
00314        bc_free_num(&first);
00315        bc_free_num(&second);
00316        bc_free_num(&result);
00317        return;
00318 }
00319 /* }}} */
00320 
00321 /* {{{ proto string bcdiv(string left_operand, string right_operand [, int scale])
00322    Returns the quotient of two arbitrary precision numbers (division) */
00323 PHP_FUNCTION(bcdiv)
00324 {
00325        char *left, *right;
00326        int left_len, right_len;
00327        long scale_param = 0;
00328        bc_num first, second, result;
00329        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00330 
00331        if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
00332               return;
00333        }
00334        
00335        if (argc == 3) {
00336               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00337        }
00338        
00339        bc_init_num(&first TSRMLS_CC);
00340        bc_init_num(&second TSRMLS_CC);
00341        bc_init_num(&result TSRMLS_CC);
00342        php_str2num(&first, left TSRMLS_CC);
00343        php_str2num(&second, right TSRMLS_CC);
00344 
00345        switch (bc_divide(first, second, &result, scale TSRMLS_CC)) {
00346               case 0: /* OK */
00347                      if (result->n_scale > scale) {
00348                             result->n_scale = scale;
00349                      }
00350                      Z_STRVAL_P(return_value) = bc_num2str(result);
00351                      Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00352                      Z_TYPE_P(return_value) = IS_STRING;
00353                      break;
00354               case -1: /* division by zero */
00355                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
00356                      break;
00357        }
00358 
00359        bc_free_num(&first);
00360        bc_free_num(&second);
00361        bc_free_num(&result);
00362        return;
00363 }
00364 /* }}} */
00365 
00366 /* {{{ proto string bcmod(string left_operand, string right_operand)
00367    Returns the modulus of the two arbitrary precision operands */
00368 PHP_FUNCTION(bcmod)
00369 {
00370        char *left, *right;
00371        int left_len, right_len;
00372        bc_num first, second, result;
00373 
00374        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &left, &left_len, &right, &right_len) == FAILURE) {
00375               return;
00376        }
00377        
00378        bc_init_num(&first TSRMLS_CC);
00379        bc_init_num(&second TSRMLS_CC);
00380        bc_init_num(&result TSRMLS_CC);
00381        bc_str2num(&first, left, 0 TSRMLS_CC);
00382        bc_str2num(&second, right, 0 TSRMLS_CC);
00383        
00384        switch (bc_modulo(first, second, &result, 0 TSRMLS_CC)) {
00385               case 0:
00386                      Z_STRVAL_P(return_value) = bc_num2str(result);
00387                      Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00388                      Z_TYPE_P(return_value) = IS_STRING;
00389                      break;
00390               case -1:
00391                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
00392                      break;
00393        }
00394        
00395        bc_free_num(&first);
00396        bc_free_num(&second);
00397        bc_free_num(&result);
00398        return;
00399 }
00400 /* }}} */
00401 
00402 /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
00403    Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
00404 PHP_FUNCTION(bcpowmod)
00405 {
00406        char *left, *right, *modulous;
00407        int left_len, right_len, modulous_len;
00408        bc_num first, second, mod, result;
00409        long scale = BCG(bc_precision);
00410        int scale_int;
00411 
00412        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &left, &left_len, &right, &right_len, &modulous, &modulous_len, &scale) == FAILURE) {
00413               return;
00414        }
00415 
00416        bc_init_num(&first TSRMLS_CC);
00417        bc_init_num(&second TSRMLS_CC);
00418        bc_init_num(&mod TSRMLS_CC);
00419        bc_init_num(&result TSRMLS_CC);
00420        php_str2num(&first, left TSRMLS_CC);
00421        php_str2num(&second, right TSRMLS_CC);
00422        php_str2num(&mod, modulous TSRMLS_CC);
00423 
00424        scale_int = (int) ((int)scale < 0) ? 0 : scale;
00425 
00426        if (bc_raisemod(first, second, mod, &result, scale_int TSRMLS_CC) != -1) {
00427               if (result->n_scale > scale) {
00428                      result->n_scale = scale;
00429               }
00430               Z_STRVAL_P(return_value) = bc_num2str(result);
00431               Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00432               Z_TYPE_P(return_value) = IS_STRING;
00433        } else {
00434               RETVAL_FALSE;
00435        }
00436        
00437        bc_free_num(&first);
00438        bc_free_num(&second);
00439        bc_free_num(&mod);
00440        bc_free_num(&result);
00441        return;
00442 }
00443 /* }}} */
00444 
00445 /* {{{ proto string bcpow(string x, string y [, int scale])
00446    Returns the value of an arbitrary precision number raised to the power of another */
00447 PHP_FUNCTION(bcpow)
00448 {
00449        char *left, *right;
00450        int left_len, right_len;
00451        long scale_param = 0;
00452        bc_num first, second, result;
00453        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00454 
00455        if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
00456               return;
00457        }
00458        
00459        if (argc == 3) {
00460               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00461        }
00462 
00463        bc_init_num(&first TSRMLS_CC);
00464        bc_init_num(&second TSRMLS_CC);
00465        bc_init_num(&result TSRMLS_CC);
00466        php_str2num(&first, left TSRMLS_CC);
00467        php_str2num(&second, right TSRMLS_CC);
00468        bc_raise (first, second, &result, scale TSRMLS_CC);
00469 
00470        if (result->n_scale > scale) {
00471               result->n_scale = scale;
00472        }
00473 
00474        Z_STRVAL_P(return_value) = bc_num2str(result);
00475        Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00476        Z_TYPE_P(return_value) = IS_STRING;
00477        bc_free_num(&first);
00478        bc_free_num(&second);
00479        bc_free_num(&result);
00480        return;
00481 }
00482 /* }}} */
00483 
00484 /* {{{ proto string bcsqrt(string operand [, int scale])
00485    Returns the square root of an arbitray precision number */
00486 PHP_FUNCTION(bcsqrt)
00487 {
00488        char *left;
00489        int left_len;
00490        long scale_param = 0;
00491        bc_num result;
00492        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00493 
00494        if (zend_parse_parameters(argc TSRMLS_CC, "s|l", &left, &left_len, &scale_param) == FAILURE) {
00495               return;
00496        }
00497        
00498        if (argc == 2) {
00499               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00500        }
00501 
00502        bc_init_num(&result TSRMLS_CC);
00503        php_str2num(&result, left TSRMLS_CC);
00504        
00505        if (bc_sqrt (&result, scale TSRMLS_CC) != 0) {
00506               if (result->n_scale > scale) {
00507                      result->n_scale = scale;
00508               }
00509               Z_STRVAL_P(return_value) = bc_num2str(result);
00510               Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
00511               Z_TYPE_P(return_value) = IS_STRING;
00512        } else {
00513               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Square root of negative number");
00514        }
00515 
00516        bc_free_num(&result);
00517        return;
00518 }
00519 /* }}} */
00520 
00521 /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
00522    Compares two arbitrary precision numbers */
00523 PHP_FUNCTION(bccomp)
00524 {
00525        char *left, *right;
00526        int left_len, right_len;
00527        long scale_param = 0;
00528        bc_num first, second;
00529        int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
00530 
00531        if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
00532               return;
00533        }
00534        
00535        if (argc == 3) {
00536               scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
00537        }
00538 
00539        bc_init_num(&first TSRMLS_CC);
00540        bc_init_num(&second TSRMLS_CC);
00541 
00542        bc_str2num(&first, left, scale TSRMLS_CC);
00543        bc_str2num(&second, right, scale TSRMLS_CC);
00544        Z_LVAL_P(return_value) = bc_compare(first, second);
00545        Z_TYPE_P(return_value) = IS_LONG;
00546 
00547        bc_free_num(&first);
00548        bc_free_num(&second);
00549        return;
00550 }
00551 /* }}} */
00552 
00553 /* {{{ proto bool bcscale(int scale)
00554    Sets default scale parameter for all bc math functions */
00555 PHP_FUNCTION(bcscale)
00556 {
00557        long new_scale;
00558        
00559        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_scale) == FAILURE) {
00560               return;
00561        }
00562 
00563        BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
00564 
00565        RETURN_TRUE;
00566 }
00567 /* }}} */
00568 
00569 
00570 #endif
00571 
00572 /*
00573  * Local variables:
00574  * tab-width: 4
00575  * c-basic-offset: 4
00576  * End:
00577  * vim600: sw=4 ts=4 fdm=marker
00578  * vim<600: sw=4 ts=4
00579  */