PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: directory - standard - math.c (source / functions) Found Hit Coverage
Test: PHP Code Coverage Lines: 461 423 91.8 %
Date: 2012-05-14 Functions: 55 54 98.2 %
Colors: not hit hit

       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                 :    | Authors: Jim Winstead <jimw@php.net>                                 |
      16                 :    |          Stig Sæther Bakken <ssb@php.net>                            |
      17                 :    |          Zeev Suraski <zeev@zend.com>                                |
      18                 :    | PHP 4.0 patches by Thies C. Arntzen <thies@thieso.net>               |
      19                 :    +----------------------------------------------------------------------+
      20                 : */
      21                 : 
      22                 : /* $Id$ */
      23                 : 
      24                 : #include "php.h"
      25                 : #include "php_math.h"
      26                 : #include "zend_multiply.h"
      27                 : 
      28                 : #include <math.h>
      29                 : #include <float.h>
      30                 : #include <stdlib.h>
      31                 : 
      32                 : #include "basic_functions.h"
      33                 : 
      34                 : /* {{{ php_intlog10abs
      35                 :    Returns floor(log10(fabs(val))), uses fast binary search */
      36            1470 : static inline int php_intlog10abs(double value) {
      37                 :         int result;
      38            1470 :         value = fabs(value);
      39                 : 
      40            1501 :         if (value < 1e-8 || value > 1e22) {
      41              31 :                 result = (int)floor(log10(value));
      42                 :         } else {
      43                 :                 static const double values[] = {
      44                 :                         1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
      45                 :                         1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,
      46                 :                         1e8,  1e9,  1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
      47                 :                         1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
      48                 :                 /* Do a binary search with 5 steps */
      49            1439 :                 result = 15;
      50            1439 :                 if (value < values[result]) {
      51            1374 :                         result -= 8;
      52                 :                 } else {
      53              65 :                         result += 8;
      54                 :                 }
      55            1439 :                 if (value < values[result]) {
      56              69 :                         result -= 4;
      57                 :                 } else {
      58            1370 :                         result += 4;
      59                 :                 }
      60            1439 :                 if (value < values[result]) {
      61             727 :                         result -= 2;
      62                 :                 } else {
      63             712 :                         result += 2;
      64                 :                 }
      65            1439 :                 if (value < values[result]) {
      66             724 :                         result -= 1;
      67                 :                 } else {
      68             715 :                         result += 1;
      69                 :                 }
      70            1439 :                 if (value < values[result]) {
      71             634 :                         result -= 1;
      72                 :                 }
      73            1439 :                 result -= 8;
      74                 :         }
      75            1470 :         return result;
      76                 : }
      77                 : /* }}} */
      78                 : 
      79                 : /* {{{ php_intpow10
      80                 :        Returns pow(10.0, (double)power), uses fast lookup table for exact powers */
      81            4314 : static inline double php_intpow10(int power) {
      82                 :         static const double powers[] = {
      83                 :                 1e0,  1e1,  1e2,  1e3,  1e4,  1e5,  1e6,  1e7,
      84                 :                 1e8,  1e9,  1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
      85                 :                 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
      86                 : 
      87                 :         /* Not in lookup table */
      88            4314 :         if (power < 0 || power > 22) {
      89              21 :                 return pow(10.0, (double)power);
      90                 :         }
      91            4293 :         return powers[power];
      92                 : }
      93                 : /* }}} */
      94                 : 
      95                 : /* {{{ php_math_is_finite */
      96            1472 : static inline int php_math_is_finite(double value) {
      97                 : #if defined(PHP_WIN32)
      98                 :         return _finite(value);
      99                 : #elif defined(isfinite)
     100            1472 :         return isfinite(value);
     101                 : #else
     102                 :         return value == value && (value == 0. || value * 2. != value);
     103                 : #endif
     104                 : }
     105                 : /* }}} */
     106                 : 
     107                 : /* {{{ php_round_helper
     108                 :        Actually performs the rounding of a value to integer in a certain mode */
     109            2865 : static inline double php_round_helper(double value, int mode) {
     110                 :         double tmp_value;
     111                 : 
     112            2865 :         if (value >= 0.0) {
     113            2801 :                 tmp_value = floor(value + 0.5);
     114            2809 :                 if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) ||
     115               4 :                         (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) ||
     116               4 :                         (mode == PHP_ROUND_HALF_ODD  && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)))
     117                 :                 {
     118               4 :                         tmp_value = tmp_value - 1.0;
     119                 :                 }
     120                 :         } else {
     121              64 :                 tmp_value = ceil(value - 0.5);
     122              72 :                 if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) ||
     123               4 :                         (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) ||
     124               4 :                         (mode == PHP_ROUND_HALF_ODD  && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0)))
     125                 :                 {
     126               4 :                         tmp_value = tmp_value + 1.0;
     127                 :                 }
     128                 :         }
     129                 : 
     130            2865 :         return tmp_value;
     131                 : }
     132                 : /* }}} */
     133                 : 
     134                 : /* {{{ _php_math_round */
     135                 : /*
     136                 :  * Rounds a number to a certain number of decimal places in a certain rounding
     137                 :  * mode. For the specifics of the algorithm, see http://wiki.php.net/rfc/rounding
     138                 :  */
     139            1472 : PHPAPI double _php_math_round(double value, int places, int mode) {
     140                 :         double f1, f2;
     141                 :         double tmp_value;
     142                 :         int precision_places;
     143                 : 
     144            1472 :         if (!php_math_is_finite(value)) {
     145               2 :                 return value;
     146                 :         }
     147                 :         
     148            1470 :         precision_places = 14 - php_intlog10abs(value);
     149                 : 
     150            1470 :         f1 = php_intpow10(abs(places));
     151                 : 
     152                 :         /* If the decimal precision guaranteed by FP arithmetic is higher than
     153                 :            the requested places BUT is small enough to make sure a non-zero value
     154                 :            is returned, pre-round the result to the precision */
     155            2892 :         if (precision_places > places && precision_places - places < 15) {
     156            1422 :                 f2 = php_intpow10(abs(precision_places));
     157            1422 :                 if (precision_places >= 0) {
     158            1416 :                         tmp_value = value * f2;
     159                 :                 } else {
     160               6 :                         tmp_value = value / f2;
     161                 :                 }
     162                 :                 /* preround the result (tmp_value will always be something * 1e14,
     163                 :                    thus never larger than 1e15 here) */
     164            1422 :                 tmp_value = php_round_helper(tmp_value, mode);
     165                 :                 /* now correctly move the decimal point */
     166            1422 :                 f2 = php_intpow10(abs(places - precision_places));
     167                 :                 /* because places < precision_places */
     168            1422 :                 tmp_value = tmp_value / f2;
     169                 :         } else {
     170                 :                 /* adjust the value */
     171              48 :                 if (places >= 0) {
     172              46 :                         tmp_value = value * f1;
     173                 :                 } else {
     174               2 :                         tmp_value = value / f1;
     175                 :                 }
     176                 :                 /* This value is beyond our precision, so rounding it is pointless */
     177              48 :                 if (fabs(tmp_value) >= 1e15) {
     178              27 :                         return value;
     179                 :                 }
     180                 :         }
     181                 : 
     182                 :         /* round the temp value */
     183            1443 :         tmp_value = php_round_helper(tmp_value, mode);
     184                 :         
     185                 :         /* see if it makes sense to use simple division to round the value */
     186            2877 :         if (abs(places) < 23) {
     187            1434 :                 if (places > 0) {
     188             169 :                         tmp_value = tmp_value / f1;
     189                 :                 } else {
     190            1265 :                         tmp_value = tmp_value * f1;
     191                 :                 }
     192                 :         } else {
     193                 :                 /* Simple division can't be used since that will cause wrong results.
     194                 :                    Instead, the number is converted to a string and back again using
     195                 :                    strtod(). strtod() will return the nearest possible FP value for
     196                 :                    that string. */
     197                 : 
     198                 :                 /* 40 Bytes should be more than enough for this format string. The
     199                 :                    float won't be larger than 1e15 anyway. But just in case, use
     200                 :                    snprintf() and make sure the buffer is zero-terminated */
     201                 :                 char buf[40];
     202               9 :                 snprintf(buf, 39, "%15fe%d", tmp_value, -places);
     203               9 :                 buf[39] = '\0';
     204               9 :                 tmp_value = zend_strtod(buf, NULL);
     205                 :                 /* couldn't convert to string and back */
     206               9 :                 if (!zend_finite(tmp_value) || zend_isnan(tmp_value)) {
     207               0 :                         tmp_value = value;
     208                 :                 }
     209                 :         }
     210                 : 
     211            1443 :         return tmp_value;
     212                 : }
     213                 : /* }}} */
     214                 : 
     215                 : /* {{{ php_asinh
     216                 : */
     217              33 : static double php_asinh(double z)
     218                 : {
     219                 : #ifdef HAVE_ASINH
     220              33 :         return(asinh(z));
     221                 : #else
     222                 :         return(log(z + sqrt(1 + pow(z, 2))) / log(M_E));
     223                 : #endif
     224                 : }
     225                 : /* }}} */
     226                 : 
     227                 : /* {{{ php_acosh
     228                 : */
     229              33 : static double php_acosh(double x)
     230                 : {
     231                 : #ifdef HAVE_ACOSH
     232              33 :         return(acosh(x));
     233                 : #else
     234                 :         return(log(x + sqrt(x * x - 1)));
     235                 : #endif
     236                 : }
     237                 : /* }}} */
     238                 : 
     239                 : /* {{{ php_atanh
     240                 : */
     241              33 : static double php_atanh(double z)
     242                 : {
     243                 : #ifdef HAVE_ATANH
     244              33 :         return(atanh(z));
     245                 : #else
     246                 :         return(0.5 * log((1 + z) / (1 - z)));
     247                 : #endif
     248                 : }
     249                 : /* }}} */
     250                 : 
     251                 : /* {{{ php_log1p
     252                 : */
     253              46 : static double php_log1p(double x)
     254                 : {
     255                 : #ifdef HAVE_LOG1P
     256              46 :         return(log1p(x));
     257                 : #else
     258                 :         return(log(1 + x));
     259                 : #endif
     260                 : }
     261                 : /* }}} */
     262                 : 
     263                 : /* {{{ php_expm1
     264                 : */
     265              45 : static double php_expm1(double x)
     266                 : {
     267                 : #if !defined(PHP_WIN32) && !defined(NETWARE)
     268              45 :         return(expm1(x));
     269                 : #else
     270                 :         return(exp(x) - 1);
     271                 : #endif
     272                 : }
     273                 : /* }}}*/
     274                 : 
     275                 : /* {{{ proto int abs(int number)
     276                 :    Return the absolute value of the number */
     277             280 : PHP_FUNCTION(abs) 
     278                 : {
     279                 :         zval **value;
     280                 :         
     281             280 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) {
     282               2 :                 return;
     283                 :         }
     284             400 :         convert_scalar_to_number_ex(value);
     285                 :         
     286             278 :         if (Z_TYPE_PP(value) == IS_DOUBLE) {
     287             211 :                 RETURN_DOUBLE(fabs(Z_DVAL_PP(value)));
     288              67 :         } else if (Z_TYPE_PP(value) == IS_LONG) {
     289              66 :                 if (Z_LVAL_PP(value) == LONG_MIN) {
     290               2 :                         RETURN_DOUBLE(-(double)LONG_MIN);
     291                 :                 } else {
     292              64 :                         RETURN_LONG(Z_LVAL_PP(value) < 0 ? -Z_LVAL_PP(value) : Z_LVAL_PP(value));
     293                 :                 }
     294                 :         }
     295               1 :         RETURN_FALSE;
     296                 : }
     297                 : /* }}} */ 
     298                 : 
     299                 : /* {{{ proto float ceil(float number)
     300                 :    Returns the next highest integer value of the number */
     301              71 : PHP_FUNCTION(ceil) 
     302                 : {
     303                 :         zval **value;
     304                 :         
     305              71 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) {
     306               2 :                 return;
     307                 :         }
     308             190 :         convert_scalar_to_number_ex(value);
     309                 : 
     310              69 :         if (Z_TYPE_PP(value) == IS_DOUBLE) {
     311              25 :                 RETURN_DOUBLE(ceil(Z_DVAL_PP(value)));
     312              44 :         } else if (Z_TYPE_PP(value) == IS_LONG) {
     313             210 :                 convert_to_double_ex(value);
     314              43 :                 RETURN_DOUBLE(Z_DVAL_PP(value));
     315                 :         }
     316               1 :         RETURN_FALSE;
     317                 : }
     318                 : /* }}} */
     319                 : 
     320                 : /* {{{ proto float floor(float number)
     321                 :    Returns the next lowest integer value from the number */
     322             435 : PHP_FUNCTION(floor)
     323                 : {
     324                 :         zval **value;
     325                 :         
     326             435 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) {
     327               2 :                 return;
     328                 :         }
     329             554 :         convert_scalar_to_number_ex(value);
     330                 : 
     331             433 :         if (Z_TYPE_PP(value) == IS_DOUBLE) {
     332             386 :                 RETURN_DOUBLE(floor(Z_DVAL_PP(value)));
     333              47 :         } else if (Z_TYPE_PP(value) == IS_LONG) {
     334             222 :                 convert_to_double_ex(value);
     335              46 :                 RETURN_DOUBLE(Z_DVAL_PP(value));
     336                 :         }
     337               1 :         RETURN_FALSE;
     338                 : }
     339                 : /* }}} */
     340                 : 
     341                 : /* {{{ proto float round(float number [, int precision [, int mode]])
     342                 :    Returns the number rounded to specified precision */
     343            1457 : PHP_FUNCTION(round)
     344                 : {
     345                 :         zval **value;
     346            1457 :         int places = 0;
     347            1457 :         long precision = 0;
     348            1457 :         long mode = PHP_ROUND_HALF_UP;
     349                 :         double return_val;
     350                 :         
     351            1457 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ll", &value, &precision, &mode) == FAILURE) {
     352               9 :                 return;
     353                 :         }
     354                 : 
     355            1448 :         if (ZEND_NUM_ARGS() >= 2) {
     356             225 :                 places = (int) precision;
     357                 :         }
     358            1719 :         convert_scalar_to_number_ex(value);
     359                 : 
     360            1448 :         switch (Z_TYPE_PP(value)) {
     361                 :                 case IS_LONG:
     362                 :                         /* Simple case - long that doesn't need to be rounded. */
     363            1292 :                         if (places >= 0) {
     364            1292 :                                 RETURN_DOUBLE((double) Z_LVAL_PP(value));
     365                 :                         }
     366                 :                         /* break omitted intentionally */
     367                 : 
     368                 :                 case IS_DOUBLE:
     369             155 :                         return_val = (Z_TYPE_PP(value) == IS_LONG) ? (double)Z_LVAL_PP(value) : Z_DVAL_PP(value);
     370             155 :                         return_val = _php_math_round(return_val, places, mode);
     371             155 :                         RETURN_DOUBLE(return_val);
     372                 :                         break;
     373                 : 
     374                 :                 default:
     375               1 :                         RETURN_FALSE;
     376                 :                         break;
     377                 :         }
     378                 : }
     379                 : /* }}} */
     380                 : 
     381                 : /* {{{ proto float sin(float number)
     382                 :    Returns the sine of the number in radians */
     383              45 : PHP_FUNCTION(sin)
     384                 : {
     385                 :         double num;
     386                 : 
     387              45 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     388               3 :                 return;
     389                 :         }
     390              42 :         RETURN_DOUBLE(sin(num));
     391                 : }
     392                 : /* }}} */
     393                 : 
     394                 : /* {{{ proto float cos(float number)
     395                 :    Returns the cosine of the number in radians */
     396              47 : PHP_FUNCTION(cos)
     397                 : {
     398                 :         double num;
     399                 :         
     400              47 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     401               3 :                 return;
     402                 :         }
     403              44 :         RETURN_DOUBLE(cos(num));
     404                 : }
     405                 : /* }}} */
     406                 : 
     407                 : /* {{{ proto float tan(float number)
     408                 :    Returns the tangent of the number in radians */
     409              37 : PHP_FUNCTION(tan)
     410                 : {
     411                 :         double num;
     412                 : 
     413              37 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     414               3 :                 return;
     415                 :         }
     416              34 :         RETURN_DOUBLE(tan(num));
     417                 : }
     418                 : /* }}} */
     419                 : 
     420                 : /* {{{ proto float asin(float number)
     421                 :    Returns the arc sine of the number in radians */
     422              36 : PHP_FUNCTION(asin)
     423                 : {
     424                 :         double num;
     425                 : 
     426              36 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     427               3 :                 return;
     428                 :         }
     429              33 :         RETURN_DOUBLE(asin(num));
     430                 : }
     431                 : /* }}} */
     432                 : 
     433                 : /* {{{ proto float acos(float number)
     434                 :    Return the arc cosine of the number in radians */
     435              41 : PHP_FUNCTION(acos)
     436                 : {
     437                 :         double num;
     438                 : 
     439              41 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     440               3 :                 return;
     441                 :         }
     442              38 :         RETURN_DOUBLE(acos(num));
     443                 : }
     444                 : /* }}} */
     445                 : 
     446                 : /* {{{ proto float atan(float number)
     447                 :    Returns the arc tangent of the number in radians */
     448              34 : PHP_FUNCTION(atan)
     449                 : {
     450                 :         double num;
     451                 : 
     452              34 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     453               3 :                 return;
     454                 :         }
     455              31 :         RETURN_DOUBLE(atan(num));
     456                 : }
     457                 : /* }}} */
     458                 : 
     459                 : /* {{{ proto float atan2(float y, float x)
     460                 :    Returns the arc tangent of y/x, with the resulting quadrant determined by the signs of y and x */
     461             364 : PHP_FUNCTION(atan2)
     462                 : {
     463                 :         double num1, num2;
     464                 : 
     465             364 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
     466              19 :                 return;
     467                 :         }
     468             345 :         RETURN_DOUBLE(atan2(num1, num2));
     469                 : }
     470                 : /* }}} */
     471                 : 
     472                 : /* {{{ proto float sinh(float number)
     473                 :    Returns the hyperbolic sine of the number, defined as (exp(number) - exp(-number))/2 */
     474              40 : PHP_FUNCTION(sinh)
     475                 : {
     476                 :         double num;
     477                 : 
     478              40 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     479               3 :                 return;
     480                 :         }
     481              37 :         RETURN_DOUBLE(sinh(num));
     482                 : }
     483                 : /* }}} */
     484                 : 
     485                 : /* {{{ proto float cosh(float number)
     486                 :    Returns the hyperbolic cosine of the number, defined as (exp(number) + exp(-number))/2 */
     487              40 : PHP_FUNCTION(cosh)
     488                 : {
     489                 :         double num;
     490                 : 
     491              40 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     492               3 :                 return;
     493                 :         }
     494              37 :         RETURN_DOUBLE(cosh(num));
     495                 : }
     496                 : /* }}} */
     497                 : 
     498                 : /* {{{ proto float tanh(float number)
     499                 :    Returns the hyperbolic tangent of the number, defined as sinh(number)/cosh(number) */
     500              40 : PHP_FUNCTION(tanh)
     501                 : {
     502                 :         double num;
     503                 : 
     504              40 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     505               3 :                 return;
     506                 :         }
     507              37 :         RETURN_DOUBLE(tanh(num));
     508                 : }
     509                 : /* }}} */
     510                 : 
     511                 : /* {{{ proto float asinh(float number)
     512                 :    Returns the inverse hyperbolic sine of the number, i.e. the value whose hyperbolic sine is number */
     513              36 : PHP_FUNCTION(asinh)
     514                 : {
     515                 :         double num;
     516                 : 
     517              36 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     518               3 :                 return;
     519                 :         }
     520              33 :         RETURN_DOUBLE(php_asinh(num));
     521                 : }
     522                 : /* }}} */
     523                 : 
     524                 : /* {{{ proto float acosh(float number)
     525                 :    Returns the inverse hyperbolic cosine of the number, i.e. the value whose hyperbolic cosine is number */
     526              36 : PHP_FUNCTION(acosh)
     527                 : {
     528                 :         double num;
     529                 :         
     530              36 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     531               3 :                 return;
     532                 :         }
     533              33 :         RETURN_DOUBLE(php_acosh(num));
     534                 : }
     535                 : /* }}} */
     536                 : 
     537                 : /* {{{ proto float atanh(float number)
     538                 :    Returns the inverse hyperbolic tangent of the number, i.e. the value whose hyperbolic tangent is number */
     539              36 : PHP_FUNCTION(atanh)
     540                 : {
     541                 :         double num;
     542                 : 
     543              36 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     544               3 :                 return;
     545                 :         }
     546              33 :         RETURN_DOUBLE(php_atanh(num));
     547                 : }
     548                 : /* }}} */
     549                 : 
     550                 : /* {{{ proto float pi(void)
     551                 :    Returns an approximation of pi */
     552               1 : PHP_FUNCTION(pi)
     553                 : {
     554               1 :         RETURN_DOUBLE(M_PI);
     555                 : }
     556                 : /* }}} */
     557                 : 
     558                 : /* {{{ proto bool is_finite(float val)
     559                 :    Returns whether argument is finite */
     560              58 : PHP_FUNCTION(is_finite)
     561                 : {
     562                 :         double dval;
     563                 : 
     564              58 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
     565              10 :                 return;
     566                 :         }
     567              48 :         RETURN_BOOL(zend_finite(dval));
     568                 : }
     569                 : /* }}} */
     570                 : 
     571                 : /* {{{ proto bool is_infinite(float val)
     572                 :    Returns whether argument is infinite */
     573              66 : PHP_FUNCTION(is_infinite)
     574                 : {
     575                 :         double dval;
     576                 : 
     577              66 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
     578              10 :                 return;
     579                 :         }
     580              56 :         RETURN_BOOL(zend_isinf(dval));
     581                 : }
     582                 : /* }}} */
     583                 : 
     584                 : /* {{{ proto bool is_nan(float val)
     585                 :    Returns whether argument is not a number */
     586              60 : PHP_FUNCTION(is_nan)
     587                 : {
     588                 :         double dval;
     589                 : 
     590              60 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
     591              10 :                 return;
     592                 :         }
     593              50 :         RETURN_BOOL(zend_isnan(dval));
     594                 : }
     595                 : /* }}} */
     596                 : 
     597                 : /* {{{ proto number pow(number base, number exponent)
     598                 :    Returns base raised to the power of exponent. Returns integer result when possible */
     599            2220 : PHP_FUNCTION(pow)
     600                 : {
     601                 :         zval *zbase, *zexp;
     602                 : 
     603            2220 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/", &zbase, &zexp) == FAILURE) {
     604               6 :                 return;
     605                 :         }
     606                 : 
     607                 :         /* make sure we're dealing with numbers */
     608            2214 :         convert_scalar_to_number(zbase TSRMLS_CC);
     609            2214 :         convert_scalar_to_number(zexp TSRMLS_CC);
     610                 : 
     611                 :         /* if both base and exponent were longs, we'll try to get a long out */
     612            2214 :         if (Z_TYPE_P(zbase) == IS_LONG && Z_TYPE_P(zexp) == IS_LONG && Z_LVAL_P(zexp) >= 0) {
     613             819 :                 long l1 = 1, l2 = Z_LVAL_P(zbase), i = Z_LVAL_P(zexp);
     614                 :                 
     615             819 :                 if (i == 0) {
     616              26 :                         RETURN_LONG(1L);
     617             793 :                 } else if (l2 == 0) {
     618              14 :                         RETURN_LONG(0);
     619                 :                 }
     620                 : 
     621                 :                 /* calculate pow(long,long) in O(log exp) operations, bail if overflow */
     622            5895 :                 while (i >= 1) {
     623                 :                         int overflow;
     624            5116 :                         double dval = 0.0;
     625                 : 
     626            5116 :                         if (i % 2) {
     627            1984 :                                 --i;
     628            1984 :                                 ZEND_SIGNED_MULTIPLY_LONG(l1,l2,l1,dval,overflow);
     629            1984 :                                 if (overflow) RETURN_DOUBLE(dval * pow(l2,i));
     630                 :                         } else {
     631            3132 :                                 i /= 2;
     632            3132 :                                 ZEND_SIGNED_MULTIPLY_LONG(l2,l2,l2,dval,overflow);
     633            3132 :                                 if (overflow) RETURN_DOUBLE((double)l1 * pow(dval,i));
     634                 :                         }
     635            5026 :                         if (i == 0) {
     636             689 :                                 RETURN_LONG(l1);
     637                 :                         }
     638                 :                 }
     639                 :         }
     640            1395 :         convert_to_double(zbase);
     641            1395 :         convert_to_double(zexp);
     642                 :         
     643            1395 :         RETURN_DOUBLE(pow(Z_DVAL_P(zbase), Z_DVAL_P(zexp)));
     644                 : }
     645                 : /* }}} */
     646                 : 
     647                 : /* {{{ proto float exp(float number)
     648                 :    Returns e raised to the power of the number */
     649             256 : PHP_FUNCTION(exp)
     650                 : {
     651                 :         double num;
     652                 : 
     653             256 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     654              10 :                 return;
     655                 :         }
     656                 : 
     657             246 :         RETURN_DOUBLE(exp(num));
     658                 : }
     659                 : /* }}} */
     660                 : 
     661                 : /* {{{ proto float expm1(float number)
     662                 :    Returns exp(number) - 1, computed in a way that accurate even when the value of number is close to zero */
     663                 : /*
     664                 :    WARNING: this function is expermental: it could change its name or 
     665                 :    disappear in the next version of PHP!
     666                 : */
     667              59 : PHP_FUNCTION(expm1)
     668                 : {
     669                 :         double num;
     670                 : 
     671              59 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     672              14 :                 return;
     673                 :         }
     674              45 :         RETURN_DOUBLE(php_expm1(num));
     675                 : }
     676                 : /* }}} */
     677                 : 
     678                 : /* {{{ proto float log1p(float number)
     679                 :    Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero */ 
     680                 : /*
     681                 :    WARNING: this function is expermental: it could change its name or 
     682                 :    disappear in the next version of PHP!
     683                 : */
     684              56 : PHP_FUNCTION(log1p)
     685                 : {
     686                 :         double num;
     687                 : 
     688              56 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     689              10 :                 return;
     690                 :         }
     691              46 :         RETURN_DOUBLE(php_log1p(num));
     692                 : }
     693                 : /* }}} */
     694                 : 
     695                 : /* {{{ proto float log(float number, [float base])
     696                 :    Returns the natural logarithm of the number, or the base log if base is specified */
     697             746 : PHP_FUNCTION(log)
     698                 : {
     699             746 :         double num, base = 0;
     700                 :         
     701             746 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|d", &num, &base) == FAILURE) {
     702              18 :                 return;
     703                 :         }
     704             728 :         if (ZEND_NUM_ARGS() == 1) {
     705             229 :                 RETURN_DOUBLE(log(num));
     706                 :         }
     707             499 :         if (base <= 0.0) {
     708              10 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0");                           
     709              10 :                 RETURN_FALSE;
     710                 :         }
     711             489 :         if (base == 1) {
     712               3 :                 RETURN_DOUBLE(php_get_nan());
     713                 :         } else {
     714             486 :                 RETURN_DOUBLE(log(num) / log(base));
     715                 :         }
     716                 : }
     717                 : /* }}} */
     718                 : 
     719                 : /* {{{ proto float log10(float number)
     720                 :    Returns the base-10 logarithm of the number */
     721              39 : PHP_FUNCTION(log10)
     722                 : {
     723                 :         double num;
     724                 : 
     725              39 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     726               3 :                 return;
     727                 :         }
     728              36 :         RETURN_DOUBLE(log10(num));
     729                 : }
     730                 : /* }}} */
     731                 : 
     732                 : /* {{{ proto float sqrt(float number)
     733                 :    Returns the square root of the number */
     734              37 : PHP_FUNCTION(sqrt)
     735                 : {
     736                 :         double num;
     737                 : 
     738              37 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
     739               3 :                 return;
     740                 :         }
     741              34 :         RETURN_DOUBLE(sqrt(num));
     742                 : }
     743                 : /* }}} */
     744                 : 
     745                 : /* {{{ proto float hypot(float num1, float num2)
     746                 :    Returns sqrt(num1*num1 + num2*num2) */ 
     747             389 : PHP_FUNCTION(hypot)
     748                 : {
     749                 :         double num1, num2;
     750                 : 
     751             389 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
     752              19 :                 return;
     753                 :         }
     754                 : #if HAVE_HYPOT
     755             370 :         RETURN_DOUBLE(hypot(num1, num2));
     756                 : #elif defined(_MSC_VER)
     757                 :         RETURN_DOUBLE(_hypot(num1, num2));
     758                 : #else
     759                 :         RETURN_DOUBLE(sqrt((num1 * num1) + (num2 * num2)));
     760                 : #endif
     761                 : }
     762                 : /* }}} */
     763                 : 
     764                 : /* {{{ proto float deg2rad(float number)
     765                 :    Converts the number in degrees to the radian equivalent */
     766              39 : PHP_FUNCTION(deg2rad)
     767                 : {
     768                 :         double deg;
     769                 : 
     770              39 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &deg) == FAILURE) {
     771               3 :                 return;
     772                 :         }
     773              36 :         RETURN_DOUBLE((deg / 180.0) * M_PI);
     774                 : }
     775                 : /* }}} */
     776                 : 
     777                 : /* {{{ proto float rad2deg(float number)
     778                 :    Converts the radian number to the equivalent number in degrees */
     779              36 : PHP_FUNCTION(rad2deg)
     780                 : {
     781                 :         double rad;
     782                 : 
     783              36 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &rad) == FAILURE) {
     784               3 :                 return;
     785                 :         }
     786              33 :         RETURN_DOUBLE((rad / M_PI) * 180);
     787                 : }
     788                 : /* }}} */
     789                 : 
     790                 : /* {{{ _php_math_basetolong */
     791                 : /*
     792                 :  * Convert a string representation of a base(2-36) number to a long.
     793                 :  */
     794               0 : PHPAPI long _php_math_basetolong(zval *arg, int base)
     795                 : {
     796               0 :         long num = 0, digit, onum;
     797                 :         int i;
     798                 :         char c, *s;
     799                 : 
     800               0 :         if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
     801               0 :                 return 0;
     802                 :         }
     803                 : 
     804               0 :         s = Z_STRVAL_P(arg);
     805                 : 
     806               0 :         for (i = Z_STRLEN_P(arg); i > 0; i--) {
     807               0 :                 c = *s++;
     808                 :                 
     809               0 :                 digit = (c >= '0' && c <= '9') ? c - '0'
     810               0 :                         : (c >= 'A' && c <= 'Z') ? c - 'A' + 10
     811               0 :                         : (c >= 'a' && c <= 'z') ? c - 'a' + 10
     812                 :                         : base;
     813                 :                 
     814               0 :                 if (digit >= base) {
     815               0 :                         continue;
     816                 :                 }
     817                 : 
     818               0 :                 onum = num;
     819               0 :                 num = num * base + digit;
     820               0 :                 if (num > onum)
     821               0 :                         continue;
     822                 : 
     823                 :                 {
     824                 :                         TSRMLS_FETCH();
     825                 : 
     826               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number '%s' is too big to fit in long", s);
     827               0 :                         return LONG_MAX;
     828                 :                 }
     829                 :         }
     830                 : 
     831               0 :         return num;
     832                 : }
     833                 : /* }}} */
     834                 : 
     835                 : /* {{{ _php_math_basetozval */
     836                 : /*
     837                 :  * Convert a string representation of a base(2-36) number to a zval.
     838                 :  */
     839             438 : PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret)
     840                 : {
     841             438 :         long num = 0;
     842             438 :         double fnum = 0;
     843                 :         int i;
     844             438 :         int mode = 0;
     845                 :         char c, *s;
     846                 :         long cutoff;
     847                 :         int cutlim;
     848                 : 
     849             438 :         if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
     850               0 :                 return FAILURE;
     851                 :         }
     852                 : 
     853             438 :         s = Z_STRVAL_P(arg);
     854                 : 
     855             438 :         cutoff = LONG_MAX / base;
     856             438 :         cutlim = LONG_MAX % base;
     857                 :         
     858            2444 :         for (i = Z_STRLEN_P(arg); i > 0; i--) {
     859            2006 :                 c = *s++;
     860                 : 
     861                 :                 /* might not work for EBCDIC */
     862            3580 :                 if (c >= '0' && c <= '9') 
     863            1574 :                         c -= '0';
     864             564 :                 else if (c >= 'A' && c <= 'Z') 
     865             132 :                         c -= 'A' - 10;
     866             546 :                 else if (c >= 'a' && c <= 'z') 
     867             246 :                         c -= 'a' - 10;
     868                 :                 else
     869              54 :                         continue;
     870                 : 
     871            1952 :                 if (c >= base)
     872             368 :                         continue;
     873                 :                 
     874            1584 :                 switch (mode) {
     875                 :                 case 0: /* Integer */
     876            1575 :                         if (num < cutoff || (num == cutoff && c <= cutlim)) {
     877            1566 :                                 num = num * base + c;
     878            1566 :                                 break;
     879                 :                         } else {
     880               9 :                                 fnum = num;
     881               9 :                                 mode = 1;
     882                 :                         }
     883                 :                         /* fall-through */
     884                 :                 case 1: /* Float */
     885              18 :                         fnum = fnum * base + c;
     886                 :                 }       
     887                 :         }
     888                 : 
     889             438 :         if (mode == 1) {
     890               9 :                 ZVAL_DOUBLE(ret, fnum);
     891                 :         } else {
     892             429 :                 ZVAL_LONG(ret, num);
     893                 :         }
     894             438 :         return SUCCESS;
     895                 : }
     896                 : /* }}} */
     897                 : 
     898                 : /* {{{ _php_math_longtobase */
     899                 : /*
     900                 :  * Convert a long to a string containing a base(2-36) representation of
     901                 :  * the number.
     902                 :  */
     903          134404 : PHPAPI char * _php_math_longtobase(zval *arg, int base)
     904                 : {
     905                 :         static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
     906                 :         char buf[(sizeof(unsigned long) << 3) + 1];
     907                 :         char *ptr, *end;
     908                 :         unsigned long value;
     909                 : 
     910          134404 :         if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) {
     911               0 :                 return STR_EMPTY_ALLOC();
     912                 :         }
     913                 : 
     914          134404 :         value = Z_LVAL_P(arg);
     915                 : 
     916          134404 :         end = ptr = buf + sizeof(buf) - 1;
     917          134404 :         *ptr = '\0';
     918                 : 
     919                 :         do {
     920          548755 :                 *--ptr = digits[value % base];
     921          548755 :                 value /= base;
     922          548755 :         } while (ptr > buf && value);
     923                 : 
     924          134404 :         return estrndup(ptr, end - ptr);
     925                 : }
     926                 : /* }}} */
     927                 : 
     928                 : /* {{{ _php_math_zvaltobase */
     929                 : /*
     930                 :  * Convert a zval to a string containing a base(2-36) representation of
     931                 :  * the number.
     932                 :  */
     933             277 : PHPAPI char * _php_math_zvaltobase(zval *arg, int base TSRMLS_DC)
     934                 : {
     935                 :         static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
     936                 : 
     937             277 :         if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
     938               0 :                 return STR_EMPTY_ALLOC();
     939                 :         }
     940                 : 
     941             277 :         if (Z_TYPE_P(arg) == IS_DOUBLE) {
     942               0 :                 double fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
     943                 :                 char *ptr, *end;
     944                 :                 char buf[(sizeof(double) << 3) + 1];
     945                 : 
     946                 :                 /* Don't try to convert +/- infinity */
     947               0 :                 if (fvalue == HUGE_VAL || fvalue == -HUGE_VAL) {
     948               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number too large");
     949               0 :                         return STR_EMPTY_ALLOC();
     950                 :                 }
     951                 : 
     952               0 :                 end = ptr = buf + sizeof(buf) - 1;
     953               0 :                 *ptr = '\0';
     954                 : 
     955                 :                 do {
     956               0 :                         *--ptr = digits[(int) fmod(fvalue, base)];
     957               0 :                         fvalue /= base;
     958               0 :                 } while (ptr > buf && fabs(fvalue) >= 1);
     959                 : 
     960               0 :                 return estrndup(ptr, end - ptr);
     961                 :         }
     962                 :         
     963             277 :         return _php_math_longtobase(arg, base);
     964                 : }       
     965                 : /* }}} */
     966                 : 
     967                 : /* {{{ proto int bindec(string binary_number)
     968                 :    Returns the decimal equivalent of the binary number */
     969              54 : PHP_FUNCTION(bindec)
     970                 : {
     971                 :         zval **arg;
     972                 :         
     973              54 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
     974               2 :                 return;
     975                 :         }
     976             211 :         convert_to_string_ex(arg);
     977              51 :         if (_php_math_basetozval(*arg, 2, return_value) == FAILURE) {
     978               0 :                 RETURN_FALSE;
     979                 :         }
     980                 : }
     981                 : /* }}} */
     982                 : 
     983                 : /* {{{ proto int hexdec(string hexadecimal_number)
     984                 :    Returns the decimal equivalent of the hexadecimal number */
     985              62 : PHP_FUNCTION(hexdec)
     986                 : {
     987                 :         zval **arg;
     988                 :         
     989              62 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
     990               2 :                 return;
     991                 :         }
     992             219 :         convert_to_string_ex(arg);
     993              59 :         if (_php_math_basetozval(*arg, 16, return_value) == FAILURE) {
     994               0 :                 RETURN_FALSE;
     995                 :         }
     996                 : }
     997                 : /* }}} */
     998                 : 
     999                 : /* {{{ proto int octdec(string octal_number)
    1000                 :    Returns the decimal equivalent of an octal string */
    1001              54 : PHP_FUNCTION(octdec)
    1002                 : {
    1003                 :         zval **arg;
    1004                 :         
    1005              54 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
    1006               2 :                 return;
    1007                 :         }
    1008             211 :         convert_to_string_ex(arg);
    1009              51 :         if (_php_math_basetozval(*arg, 8, return_value) == FAILURE) {
    1010               0 :                 RETURN_FALSE;
    1011                 :         }
    1012                 : }
    1013                 : /* }}} */
    1014                 : 
    1015                 : /* {{{ proto string decbin(int decimal_number)
    1016                 :    Returns a string containing a binary representation of the number */
    1017            2581 : PHP_FUNCTION(decbin)
    1018                 : {
    1019                 :         zval **arg;
    1020                 :         char *result;
    1021                 : 
    1022            2581 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
    1023               0 :                 return;
    1024                 :         }
    1025            2752 :         convert_to_long_ex(arg);
    1026            2581 :         result = _php_math_longtobase(*arg, 2);
    1027            2581 :         RETURN_STRING(result, 0);
    1028                 : }
    1029                 : /* }}} */
    1030                 : 
    1031                 : /* {{{ proto string decoct(int decimal_number)
    1032                 :    Returns a string containing an octal representation of the given number */
    1033             319 : PHP_FUNCTION(decoct)
    1034                 : {
    1035                 :         zval **arg;
    1036                 :         char *result;
    1037                 : 
    1038             319 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
    1039               2 :                 return;
    1040                 :         }
    1041             488 :         convert_to_long_ex(arg);
    1042             317 :         result = _php_math_longtobase(*arg, 8);
    1043             317 :         RETURN_STRING(result, 0);
    1044                 : }
    1045                 : /* }}} */
    1046                 : 
    1047                 : /* {{{ proto string dechex(int decimal_number)
    1048                 :    Returns a string containing a hexadecimal representation of the given number */
    1049          131231 : PHP_FUNCTION(dechex)
    1050                 : {
    1051                 :         zval **arg;
    1052                 :         char *result;
    1053                 : 
    1054          131231 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
    1055               2 :                 return;
    1056                 :         }
    1057          131400 :         convert_to_long_ex(arg);
    1058          131229 :         result = _php_math_longtobase(*arg, 16);
    1059          131229 :         RETURN_STRING(result, 0);
    1060                 : }
    1061                 : /* }}} */
    1062                 : 
    1063                 : /* {{{ proto string base_convert(string number, int frombase, int tobase)
    1064                 :    Converts a number in a string from any base <= 36 to any base <= 36 */
    1065             329 : PHP_FUNCTION(base_convert)
    1066                 : {
    1067                 :         zval **number, temp;
    1068                 :         long frombase, tobase;
    1069                 :         char *result;
    1070                 : 
    1071             329 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zll", &number, &frombase, &tobase) == FAILURE) {
    1072              15 :                 return;
    1073                 :         }
    1074            1152 :         convert_to_string_ex(number);
    1075                 :         
    1076             313 :         if (frombase < 2 || frombase > 36) {
    1077              18 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `from base' (%ld)", frombase);
    1078              18 :                 RETURN_FALSE;
    1079                 :         }
    1080             295 :         if (tobase < 2 || tobase > 36) {
    1081              18 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `to base' (%ld)", tobase);
    1082              18 :                 RETURN_FALSE;
    1083                 :         }
    1084                 : 
    1085             277 :         if(_php_math_basetozval(*number, frombase, &temp) == FAILURE) {
    1086               0 :                 RETURN_FALSE;
    1087                 :         }
    1088             277 :         result = _php_math_zvaltobase(&temp, tobase TSRMLS_CC);
    1089             277 :         RETVAL_STRING(result, 0);
    1090                 : } 
    1091                 : /* }}} */
    1092                 : 
    1093                 : /* {{{ _php_math_number_format 
    1094                 : */
    1095            1317 : PHPAPI char *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
    1096                 : {
    1097            1317 :         char *tmpbuf = NULL, *resbuf;
    1098                 :         char *s, *t;  /* source, target */
    1099                 :         char *dp;
    1100                 :         int integral;
    1101            1317 :         int tmplen, reslen=0;
    1102            1317 :         int count=0;
    1103            1317 :         int is_negative=0;
    1104                 : 
    1105            1317 :         if (d < 0) {
    1106             364 :                 is_negative = 1;
    1107             364 :                 d = -d;
    1108                 :         }
    1109                 : 
    1110            1317 :         dec = MAX(0, dec);
    1111            1317 :         d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);
    1112                 : 
    1113            1317 :         tmplen = spprintf(&tmpbuf, 0, "%.*F", dec, d);
    1114                 : 
    1115            1317 :         if (tmpbuf == NULL || !isdigit((int)tmpbuf[0])) {
    1116               2 :                 return tmpbuf;
    1117                 :         }
    1118                 : 
    1119                 :         /* find decimal point, if expected */
    1120            1315 :         if (dec) {
    1121              88 :                 dp = strpbrk(tmpbuf, ".,");
    1122                 :         } else {
    1123            1227 :                 dp = NULL;
    1124                 :         }
    1125                 : 
    1126                 :         /* calculate the length of the return buffer */
    1127            1315 :         if (dp) {
    1128              88 :                 integral = dp - tmpbuf;
    1129                 :         } else {
    1130                 :                 /* no decimal point was found */
    1131            1227 :                 integral = tmplen;
    1132                 :         }
    1133                 : 
    1134                 :         /* allow for thousand separators */
    1135            1315 :         if (thousand_sep) {
    1136            1313 :                 integral += (integral-1) / 3;
    1137                 :         }
    1138                 :         
    1139            1315 :         reslen = integral;
    1140                 :         
    1141            1315 :         if (dec) {
    1142              88 :                 reslen += dec;
    1143                 : 
    1144              88 :                 if (dec_point) {
    1145              84 :                         reslen++;
    1146                 :                 }
    1147                 :         }
    1148                 : 
    1149                 :         /* add a byte for minus sign */
    1150            1315 :         if (is_negative) {
    1151             364 :                 reslen++;
    1152                 :         }
    1153            1315 :         resbuf = (char *) emalloc(reslen+1); /* +1 for NUL terminator */
    1154                 : 
    1155            1315 :         s = tmpbuf+tmplen-1;
    1156            1315 :         t = resbuf+reslen;
    1157            1315 :         *t-- = '\0';
    1158                 : 
    1159                 :         /* copy the decimal places.
    1160                 :          * Take care, as the sprintf implementation may return less places than
    1161                 :          * we requested due to internal buffer limitations */
    1162            1315 :         if (dec) {
    1163              88 :                 int declen = dp ? s - dp : 0;
    1164              88 :                 int topad = dec > declen ? dec - declen : 0;
    1165                 : 
    1166                 :                 /* pad with '0's */
    1167            4314 :                 while (topad--) {
    1168            4138 :                         *t-- = '0';
    1169                 :                 }
    1170                 :                 
    1171              88 :                 if (dp) {
    1172              88 :                         s -= declen + 1; /* +1 to skip the point */
    1173              88 :                         t -= declen;
    1174                 : 
    1175                 :                         /* now copy the chars after the point */
    1176              88 :                         memcpy(t + 1, dp + 1, declen);
    1177                 :                 }
    1178                 : 
    1179                 :                 /* add decimal point */
    1180              88 :                 if (dec_point) {
    1181              84 :                         *t-- = dec_point;
    1182                 :                 }
    1183                 :         }
    1184                 : 
    1185                 :         /* copy the numbers before the decimal point, adding thousand
    1186                 :          * separator every three digits */
    1187            8323 :         while(s >= tmpbuf) {
    1188            5693 :                 *t-- = *s--;
    1189            5693 :                 if (thousand_sep && (++count%3)==0 && s>=tmpbuf) {
    1190            1062 :                         *t-- = thousand_sep;
    1191                 :                 }
    1192                 :         }
    1193                 : 
    1194                 :         /* and a minus sign, if needed */
    1195            1315 :         if (is_negative) {
    1196             364 :                 *t-- = '-';
    1197                 :         }
    1198                 : 
    1199            1315 :         efree(tmpbuf);
    1200                 :         
    1201            1315 :         return resbuf;
    1202                 : }
    1203                 : /* }}} */
    1204                 : 
    1205                 : /* {{{ proto string number_format(float number [, int num_decimal_places [, string dec_seperator, string thousands_seperator]])
    1206                 :    Formats a number with grouped thousands */
    1207            1320 : PHP_FUNCTION(number_format)
    1208                 : {
    1209                 :         double num;
    1210            1320 :         long dec = 0;
    1211            1320 :         char *thousand_sep = NULL, *dec_point = NULL;
    1212            1320 :         char thousand_sep_chr = ',', dec_point_chr = '.';
    1213            1320 :         int thousand_sep_len = 0, dec_point_len = 0;
    1214                 :         
    1215            1320 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|ls!s!", &num, &dec, &dec_point, &dec_point_len, &thousand_sep, &thousand_sep_len) == FAILURE) {
    1216               2 :                 return;
    1217                 :         }
    1218                 : 
    1219            1318 :         switch(ZEND_NUM_ARGS()) {
    1220                 :         case 1:
    1221              24 :                 RETURN_STRING(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr), 0);
    1222                 :                 break;
    1223                 :         case 2:
    1224              35 :                 RETURN_STRING(_php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr), 0);
    1225                 :                 break;
    1226                 :         case 4:
    1227            1258 :                 if (dec_point != NULL) {
    1228            1257 :                         if (dec_point_len) {
    1229            1249 :                                 dec_point_chr = dec_point[0];
    1230                 :                         } else {
    1231               8 :                                 dec_point_chr = 0;
    1232                 :                         }
    1233                 :                 }
    1234            1258 :                 if (thousand_sep != NULL) {
    1235            1258 :                         if (thousand_sep_len) {
    1236            1256 :                                 thousand_sep_chr = thousand_sep[0];
    1237                 :                         } else {
    1238               2 :                                 thousand_sep_chr = 0;   
    1239                 :                         }
    1240                 :                 }
    1241            1258 :                 RETURN_STRING(_php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr), 0);
    1242                 :                 break;
    1243                 :         default:
    1244               1 :                 WRONG_PARAM_COUNT;
    1245                 :                 break;
    1246                 :         }
    1247                 : }
    1248                 : /* }}} */
    1249                 : 
    1250                 : /* {{{ proto float fmod(float x, float y)
    1251                 :    Returns the remainder of dividing x by y as a float */
    1252             364 : PHP_FUNCTION(fmod)
    1253                 : {
    1254                 :         double num1, num2;
    1255                 : 
    1256             364 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd",  &num1, &num2) == FAILURE) {
    1257              19 :                 return;
    1258                 :         }
    1259             345 :         RETURN_DOUBLE(fmod(num1, num2));
    1260                 : }
    1261                 : /* }}} */
    1262                 : 
    1263                 : 
    1264                 : 
    1265                 : /*
    1266                 :  * Local variables:
    1267                 :  * tab-width: 4
    1268                 :  * c-basic-offset: 4
    1269                 :  * End:
    1270                 :  * vim600: fdm=marker
    1271                 :  * vim: noet sw=4 ts=4
    1272                 :  */

Generated by: LCOV version 1.7

Generated at Mon, 14 May 2012 16:50:24 +0000 (42 hours ago)

Copyright © 2005-2012 The PHP Group
All rights reserved.