root/ext/standard/math.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_intlog10abs
  2. php_intpow10
  3. php_math_is_finite
  4. php_round_helper
  5. _php_math_round
  6. php_asinh
  7. php_acosh
  8. php_atanh
  9. php_log1p
  10. php_expm1
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. PHP_FUNCTION
  23. PHP_FUNCTION
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. PHP_FUNCTION
  27. PHP_FUNCTION
  28. PHP_FUNCTION
  29. PHP_FUNCTION
  30. PHP_FUNCTION
  31. PHP_FUNCTION
  32. PHP_FUNCTION
  33. PHP_FUNCTION
  34. PHP_FUNCTION
  35. PHP_FUNCTION
  36. PHP_FUNCTION
  37. PHP_FUNCTION
  38. PHP_FUNCTION
  39. PHP_FUNCTION
  40. PHP_FUNCTION
  41. PHP_FUNCTION
  42. _php_math_basetolong
  43. _php_math_basetozval
  44. _php_math_longtobase
  45. _php_math_zvaltobase
  46. PHP_FUNCTION
  47. PHP_FUNCTION
  48. PHP_FUNCTION
  49. PHP_FUNCTION
  50. PHP_FUNCTION
  51. PHP_FUNCTION
  52. PHP_FUNCTION
  53. _php_math_number_format
  54. _php_math_number_format_ex
  55. PHP_FUNCTION
  56. PHP_FUNCTION
  57. PHP_FUNCTION

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

/* [<][>][^][v][top][bottom][index][help] */