Annotation of embedaddon/php/ext/standard/math.c, revision 1.1.1.4

1.1       misho       1: /*
                      2:    +----------------------------------------------------------------------+
                      3:    | PHP Version 5                                                        |
                      4:    +----------------------------------------------------------------------+
1.1.1.4 ! misho       5:    | Copyright (c) 1997-2014 The PHP Group                                |
1.1       misho       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: 
1.1.1.2   misho      22: /* $Id$ */
1.1       misho      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: static inline int php_intlog10abs(double value) {
                     37:        int result;
                     38:        value = fabs(value);
                     39: 
1.1.1.3   misho      40:        if (value < 1e-8 || value > 1e22) {
1.1       misho      41:                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 */
1.1.1.3   misho      49:                result = 15;
1.1       misho      50:                if (value < values[result]) {
                     51:                        result -= 8;
                     52:                } else {
                     53:                        result += 8;
                     54:                }
                     55:                if (value < values[result]) {
                     56:                        result -= 4;
                     57:                } else {
                     58:                        result += 4;
                     59:                }
                     60:                if (value < values[result]) {
                     61:                        result -= 2;
                     62:                } else {
                     63:                        result += 2;
                     64:                }
                     65:                if (value < values[result]) {
                     66:                        result -= 1;
                     67:                } else {
                     68:                        result += 1;
                     69:                }
                     70:                if (value < values[result]) {
                     71:                        result -= 1;
                     72:                }
                     73:                result -= 8;
                     74:        }
                     75:        return result;
                     76: }
                     77: /* }}} */
                     78: 
                     79: /* {{{ php_intpow10
                     80:        Returns pow(10.0, (double)power), uses fast lookup table for exact powers */
                     81: 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:        if (power < 0 || power > 22) {
                     89:                return pow(10.0, (double)power);
                     90:        }
                     91:        return powers[power];
                     92: }
                     93: /* }}} */
                     94: 
                     95: /* {{{ php_math_is_finite */
                     96: static inline int php_math_is_finite(double value) {
                     97: #if defined(PHP_WIN32)
                     98:        return _finite(value);
                     99: #elif defined(isfinite)
                    100:        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: static inline double php_round_helper(double value, int mode) {
                    110:        double tmp_value;
                    111: 
                    112:        if (value >= 0.0) {
                    113:                tmp_value = floor(value + 0.5);
                    114:                if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) ||
                    115:                        (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) ||
                    116:                        (mode == PHP_ROUND_HALF_ODD  && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)))
                    117:                {
                    118:                        tmp_value = tmp_value - 1.0;
                    119:                }
                    120:        } else {
                    121:                tmp_value = ceil(value - 0.5);
                    122:                if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) ||
                    123:                        (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) ||
                    124:                        (mode == PHP_ROUND_HALF_ODD  && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0)))
                    125:                {
                    126:                        tmp_value = tmp_value + 1.0;
                    127:                }
                    128:        }
                    129: 
                    130:        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: 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:        if (!php_math_is_finite(value)) {
                    145:                return value;
                    146:        }
                    147:        
                    148:        precision_places = 14 - php_intlog10abs(value);
                    149: 
                    150:        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:        if (precision_places > places && precision_places - places < 15) {
                    156:                f2 = php_intpow10(abs(precision_places));
                    157:                if (precision_places >= 0) {
                    158:                        tmp_value = value * f2;
                    159:                } else {
                    160:                        tmp_value = value / f2;
                    161:                }
                    162:                /* preround the result (tmp_value will always be something * 1e14,
                    163:                   thus never larger than 1e15 here) */
                    164:                tmp_value = php_round_helper(tmp_value, mode);
                    165:                /* now correctly move the decimal point */
                    166:                f2 = php_intpow10(abs(places - precision_places));
                    167:                /* because places < precision_places */
                    168:                tmp_value = tmp_value / f2;
                    169:        } else {
                    170:                /* adjust the value */
                    171:                if (places >= 0) {
                    172:                        tmp_value = value * f1;
                    173:                } else {
                    174:                        tmp_value = value / f1;
                    175:                }
                    176:                /* This value is beyond our precision, so rounding it is pointless */
                    177:                if (fabs(tmp_value) >= 1e15) {
                    178:                        return value;
                    179:                }
                    180:        }
                    181: 
                    182:        /* round the temp value */
                    183:        tmp_value = php_round_helper(tmp_value, mode);
                    184:        
                    185:        /* see if it makes sense to use simple division to round the value */
                    186:        if (abs(places) < 23) {
                    187:                if (places > 0) {
                    188:                        tmp_value = tmp_value / f1;
                    189:                } else {
                    190:                        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:                snprintf(buf, 39, "%15fe%d", tmp_value, -places);
                    203:                buf[39] = '\0';
                    204:                tmp_value = zend_strtod(buf, NULL);
                    205:                /* couldn't convert to string and back */
                    206:                if (!zend_finite(tmp_value) || zend_isnan(tmp_value)) {
                    207:                        tmp_value = value;
                    208:                }
                    209:        }
                    210: 
                    211:        return tmp_value;
                    212: }
                    213: /* }}} */
                    214: 
                    215: /* {{{ php_asinh
                    216: */
                    217: static double php_asinh(double z)
                    218: {
                    219: #ifdef HAVE_ASINH
                    220:        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: static double php_acosh(double x)
                    230: {
                    231: #ifdef HAVE_ACOSH
                    232:        return(acosh(x));
                    233: #else
                    234:        return(log(x + sqrt(x * x - 1)));
                    235: #endif
                    236: }
                    237: /* }}} */
                    238: 
                    239: /* {{{ php_atanh
                    240: */
                    241: static double php_atanh(double z)
                    242: {
                    243: #ifdef HAVE_ATANH
                    244:        return(atanh(z));
                    245: #else
                    246:        return(0.5 * log((1 + z) / (1 - z)));
                    247: #endif
                    248: }
                    249: /* }}} */
                    250: 
                    251: /* {{{ php_log1p
                    252: */
                    253: static double php_log1p(double x)
                    254: {
                    255: #ifdef HAVE_LOG1P
                    256:        return(log1p(x));
                    257: #else
                    258:        return(log(1 + x));
                    259: #endif
                    260: }
                    261: /* }}} */
                    262: 
                    263: /* {{{ php_expm1
                    264: */
                    265: static double php_expm1(double x)
                    266: {
                    267: #if !defined(PHP_WIN32) && !defined(NETWARE)
                    268:        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: PHP_FUNCTION(abs) 
                    278: {
                    279:        zval **value;
                    280:        
                    281:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) {
                    282:                return;
                    283:        }
                    284:        convert_scalar_to_number_ex(value);
                    285:        
                    286:        if (Z_TYPE_PP(value) == IS_DOUBLE) {
                    287:                RETURN_DOUBLE(fabs(Z_DVAL_PP(value)));
                    288:        } else if (Z_TYPE_PP(value) == IS_LONG) {
                    289:                if (Z_LVAL_PP(value) == LONG_MIN) {
                    290:                        RETURN_DOUBLE(-(double)LONG_MIN);
                    291:                } else {
                    292:                        RETURN_LONG(Z_LVAL_PP(value) < 0 ? -Z_LVAL_PP(value) : Z_LVAL_PP(value));
                    293:                }
                    294:        }
                    295:        RETURN_FALSE;
                    296: }
                    297: /* }}} */ 
                    298: 
                    299: /* {{{ proto float ceil(float number)
                    300:    Returns the next highest integer value of the number */
                    301: PHP_FUNCTION(ceil) 
                    302: {
                    303:        zval **value;
                    304:        
                    305:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) {
                    306:                return;
                    307:        }
                    308:        convert_scalar_to_number_ex(value);
                    309: 
                    310:        if (Z_TYPE_PP(value) == IS_DOUBLE) {
                    311:                RETURN_DOUBLE(ceil(Z_DVAL_PP(value)));
                    312:        } else if (Z_TYPE_PP(value) == IS_LONG) {
                    313:                convert_to_double_ex(value);
                    314:                RETURN_DOUBLE(Z_DVAL_PP(value));
                    315:        }
                    316:        RETURN_FALSE;
                    317: }
                    318: /* }}} */
                    319: 
                    320: /* {{{ proto float floor(float number)
                    321:    Returns the next lowest integer value from the number */
                    322: PHP_FUNCTION(floor)
                    323: {
                    324:        zval **value;
                    325:        
                    326:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &value) == FAILURE) {
                    327:                return;
                    328:        }
                    329:        convert_scalar_to_number_ex(value);
                    330: 
                    331:        if (Z_TYPE_PP(value) == IS_DOUBLE) {
                    332:                RETURN_DOUBLE(floor(Z_DVAL_PP(value)));
                    333:        } else if (Z_TYPE_PP(value) == IS_LONG) {
                    334:                convert_to_double_ex(value);
                    335:                RETURN_DOUBLE(Z_DVAL_PP(value));
                    336:        }
                    337:        RETURN_FALSE;
                    338: }
                    339: /* }}} */
                    340: 
                    341: /* {{{ proto float round(float number [, int precision [, int mode]])
                    342:    Returns the number rounded to specified precision */
                    343: PHP_FUNCTION(round)
                    344: {
                    345:        zval **value;
                    346:        int places = 0;
                    347:        long precision = 0;
                    348:        long mode = PHP_ROUND_HALF_UP;
                    349:        double return_val;
                    350:        
                    351:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|ll", &value, &precision, &mode) == FAILURE) {
                    352:                return;
                    353:        }
                    354: 
                    355:        if (ZEND_NUM_ARGS() >= 2) {
                    356:                places = (int) precision;
                    357:        }
                    358:        convert_scalar_to_number_ex(value);
                    359: 
                    360:        switch (Z_TYPE_PP(value)) {
                    361:                case IS_LONG:
                    362:                        /* Simple case - long that doesn't need to be rounded. */
                    363:                        if (places >= 0) {
                    364:                                RETURN_DOUBLE((double) Z_LVAL_PP(value));
                    365:                        }
                    366:                        /* break omitted intentionally */
                    367: 
                    368:                case IS_DOUBLE:
                    369:                        return_val = (Z_TYPE_PP(value) == IS_LONG) ? (double)Z_LVAL_PP(value) : Z_DVAL_PP(value);
                    370:                        return_val = _php_math_round(return_val, places, mode);
                    371:                        RETURN_DOUBLE(return_val);
                    372:                        break;
                    373: 
                    374:                default:
                    375:                        RETURN_FALSE;
                    376:                        break;
                    377:        }
                    378: }
                    379: /* }}} */
                    380: 
                    381: /* {{{ proto float sin(float number)
                    382:    Returns the sine of the number in radians */
                    383: PHP_FUNCTION(sin)
                    384: {
                    385:        double num;
                    386: 
                    387:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    388:                return;
                    389:        }
                    390:        RETURN_DOUBLE(sin(num));
                    391: }
                    392: /* }}} */
                    393: 
                    394: /* {{{ proto float cos(float number)
                    395:    Returns the cosine of the number in radians */
                    396: PHP_FUNCTION(cos)
                    397: {
                    398:        double num;
                    399:        
                    400:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    401:                return;
                    402:        }
                    403:        RETURN_DOUBLE(cos(num));
                    404: }
                    405: /* }}} */
                    406: 
                    407: /* {{{ proto float tan(float number)
                    408:    Returns the tangent of the number in radians */
                    409: PHP_FUNCTION(tan)
                    410: {
                    411:        double num;
                    412: 
                    413:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    414:                return;
                    415:        }
                    416:        RETURN_DOUBLE(tan(num));
                    417: }
                    418: /* }}} */
                    419: 
                    420: /* {{{ proto float asin(float number)
                    421:    Returns the arc sine of the number in radians */
                    422: PHP_FUNCTION(asin)
                    423: {
                    424:        double num;
                    425: 
                    426:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    427:                return;
                    428:        }
                    429:        RETURN_DOUBLE(asin(num));
                    430: }
                    431: /* }}} */
                    432: 
                    433: /* {{{ proto float acos(float number)
                    434:    Return the arc cosine of the number in radians */
                    435: PHP_FUNCTION(acos)
                    436: {
                    437:        double num;
                    438: 
                    439:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    440:                return;
                    441:        }
                    442:        RETURN_DOUBLE(acos(num));
                    443: }
                    444: /* }}} */
                    445: 
                    446: /* {{{ proto float atan(float number)
                    447:    Returns the arc tangent of the number in radians */
                    448: PHP_FUNCTION(atan)
                    449: {
                    450:        double num;
                    451: 
                    452:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    453:                return;
                    454:        }
                    455:        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: PHP_FUNCTION(atan2)
                    462: {
                    463:        double num1, num2;
                    464: 
                    465:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
                    466:                return;
                    467:        }
                    468:        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: PHP_FUNCTION(sinh)
                    475: {
                    476:        double num;
                    477: 
                    478:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    479:                return;
                    480:        }
                    481:        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: PHP_FUNCTION(cosh)
                    488: {
                    489:        double num;
                    490: 
                    491:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    492:                return;
                    493:        }
                    494:        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: PHP_FUNCTION(tanh)
                    501: {
                    502:        double num;
                    503: 
                    504:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    505:                return;
                    506:        }
                    507:        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: PHP_FUNCTION(asinh)
                    514: {
                    515:        double num;
                    516: 
                    517:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    518:                return;
                    519:        }
                    520:        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: PHP_FUNCTION(acosh)
                    527: {
                    528:        double num;
                    529:        
                    530:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    531:                return;
                    532:        }
                    533:        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: PHP_FUNCTION(atanh)
                    540: {
                    541:        double num;
                    542: 
                    543:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    544:                return;
                    545:        }
                    546:        RETURN_DOUBLE(php_atanh(num));
                    547: }
                    548: /* }}} */
                    549: 
                    550: /* {{{ proto float pi(void)
                    551:    Returns an approximation of pi */
                    552: PHP_FUNCTION(pi)
                    553: {
                    554:        RETURN_DOUBLE(M_PI);
                    555: }
                    556: /* }}} */
                    557: 
                    558: /* {{{ proto bool is_finite(float val)
                    559:    Returns whether argument is finite */
                    560: PHP_FUNCTION(is_finite)
                    561: {
                    562:        double dval;
                    563: 
                    564:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
                    565:                return;
                    566:        }
                    567:        RETURN_BOOL(zend_finite(dval));
                    568: }
                    569: /* }}} */
                    570: 
                    571: /* {{{ proto bool is_infinite(float val)
                    572:    Returns whether argument is infinite */
                    573: PHP_FUNCTION(is_infinite)
                    574: {
                    575:        double dval;
                    576: 
                    577:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
                    578:                return;
                    579:        }
                    580:        RETURN_BOOL(zend_isinf(dval));
                    581: }
                    582: /* }}} */
                    583: 
                    584: /* {{{ proto bool is_nan(float val)
                    585:    Returns whether argument is not a number */
                    586: PHP_FUNCTION(is_nan)
                    587: {
                    588:        double dval;
                    589: 
                    590:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
                    591:                return;
                    592:        }
                    593:        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: PHP_FUNCTION(pow)
                    600: {
                    601:        zval *zbase, *zexp;
                    602: 
                    603:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/", &zbase, &zexp) == FAILURE) {
                    604:                return;
                    605:        }
                    606: 
                    607:        /* make sure we're dealing with numbers */
                    608:        convert_scalar_to_number(zbase TSRMLS_CC);
                    609:        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:        if (Z_TYPE_P(zbase) == IS_LONG && Z_TYPE_P(zexp) == IS_LONG && Z_LVAL_P(zexp) >= 0) {
                    613:                long l1 = 1, l2 = Z_LVAL_P(zbase), i = Z_LVAL_P(zexp);
                    614:                
                    615:                if (i == 0) {
                    616:                        RETURN_LONG(1L);
                    617:                } else if (l2 == 0) {
                    618:                        RETURN_LONG(0);
                    619:                }
                    620: 
                    621:                /* calculate pow(long,long) in O(log exp) operations, bail if overflow */
                    622:                while (i >= 1) {
1.1.1.2   misho     623:                        long overflow;
1.1       misho     624:                        double dval = 0.0;
                    625: 
                    626:                        if (i % 2) {
                    627:                                --i;
                    628:                                ZEND_SIGNED_MULTIPLY_LONG(l1,l2,l1,dval,overflow);
                    629:                                if (overflow) RETURN_DOUBLE(dval * pow(l2,i));
                    630:                        } else {
                    631:                                i /= 2;
                    632:                                ZEND_SIGNED_MULTIPLY_LONG(l2,l2,l2,dval,overflow);
                    633:                                if (overflow) RETURN_DOUBLE((double)l1 * pow(dval,i));
                    634:                        }
                    635:                        if (i == 0) {
                    636:                                RETURN_LONG(l1);
                    637:                        }
                    638:                }
                    639:        }
                    640:        convert_to_double(zbase);
                    641:        convert_to_double(zexp);
                    642:        
                    643:        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: PHP_FUNCTION(exp)
                    650: {
                    651:        double num;
                    652: 
                    653:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    654:                return;
                    655:        }
                    656: 
                    657:        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: PHP_FUNCTION(expm1)
                    668: {
                    669:        double num;
                    670: 
                    671:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    672:                return;
                    673:        }
                    674:        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: PHP_FUNCTION(log1p)
                    685: {
                    686:        double num;
                    687: 
                    688:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    689:                return;
                    690:        }
                    691:        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: PHP_FUNCTION(log)
                    698: {
                    699:        double num, base = 0;
                    700:        
                    701:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|d", &num, &base) == FAILURE) {
                    702:                return;
                    703:        }
                    704:        if (ZEND_NUM_ARGS() == 1) {
                    705:                RETURN_DOUBLE(log(num));
                    706:        }
                    707:        if (base <= 0.0) {
                    708:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0");                             
                    709:                RETURN_FALSE;
                    710:        }
                    711:        if (base == 1) {
                    712:                RETURN_DOUBLE(php_get_nan());
                    713:        } else {
                    714:                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: PHP_FUNCTION(log10)
                    722: {
                    723:        double num;
                    724: 
                    725:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    726:                return;
                    727:        }
                    728:        RETURN_DOUBLE(log10(num));
                    729: }
                    730: /* }}} */
                    731: 
                    732: /* {{{ proto float sqrt(float number)
                    733:    Returns the square root of the number */
                    734: PHP_FUNCTION(sqrt)
                    735: {
                    736:        double num;
                    737: 
                    738:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
                    739:                return;
                    740:        }
                    741:        RETURN_DOUBLE(sqrt(num));
                    742: }
                    743: /* }}} */
                    744: 
                    745: /* {{{ proto float hypot(float num1, float num2)
                    746:    Returns sqrt(num1*num1 + num2*num2) */ 
                    747: PHP_FUNCTION(hypot)
                    748: {
                    749:        double num1, num2;
                    750: 
                    751:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
                    752:                return;
                    753:        }
                    754: #if HAVE_HYPOT
                    755:        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: PHP_FUNCTION(deg2rad)
                    767: {
                    768:        double deg;
                    769: 
                    770:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &deg) == FAILURE) {
                    771:                return;
                    772:        }
                    773:        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: PHP_FUNCTION(rad2deg)
                    780: {
                    781:        double rad;
                    782: 
                    783:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &rad) == FAILURE) {
                    784:                return;
                    785:        }
                    786:        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: PHPAPI long _php_math_basetolong(zval *arg, int base)
                    795: {
                    796:        long num = 0, digit, onum;
                    797:        int i;
                    798:        char c, *s;
                    799: 
                    800:        if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
                    801:                return 0;
                    802:        }
                    803: 
                    804:        s = Z_STRVAL_P(arg);
                    805: 
                    806:        for (i = Z_STRLEN_P(arg); i > 0; i--) {
                    807:                c = *s++;
                    808:                
                    809:                digit = (c >= '0' && c <= '9') ? c - '0'
                    810:                        : (c >= 'A' && c <= 'Z') ? c - 'A' + 10
                    811:                        : (c >= 'a' && c <= 'z') ? c - 'a' + 10
                    812:                        : base;
                    813:                
                    814:                if (digit >= base) {
                    815:                        continue;
                    816:                }
                    817: 
                    818:                onum = num;
                    819:                num = num * base + digit;
                    820:                if (num > onum)
                    821:                        continue;
                    822: 
                    823:                {
                    824:                        TSRMLS_FETCH();
                    825: 
                    826:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number '%s' is too big to fit in long", s);
                    827:                        return LONG_MAX;
                    828:                }
                    829:        }
                    830: 
                    831:        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: PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret)
                    840: {
                    841:        long num = 0;
                    842:        double fnum = 0;
                    843:        int i;
                    844:        int mode = 0;
                    845:        char c, *s;
                    846:        long cutoff;
                    847:        int cutlim;
                    848: 
                    849:        if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
                    850:                return FAILURE;
                    851:        }
                    852: 
                    853:        s = Z_STRVAL_P(arg);
                    854: 
                    855:        cutoff = LONG_MAX / base;
                    856:        cutlim = LONG_MAX % base;
                    857:        
                    858:        for (i = Z_STRLEN_P(arg); i > 0; i--) {
                    859:                c = *s++;
                    860: 
                    861:                /* might not work for EBCDIC */
                    862:                if (c >= '0' && c <= '9') 
                    863:                        c -= '0';
                    864:                else if (c >= 'A' && c <= 'Z') 
                    865:                        c -= 'A' - 10;
                    866:                else if (c >= 'a' && c <= 'z') 
                    867:                        c -= 'a' - 10;
                    868:                else
                    869:                        continue;
                    870: 
                    871:                if (c >= base)
                    872:                        continue;
                    873:                
                    874:                switch (mode) {
                    875:                case 0: /* Integer */
                    876:                        if (num < cutoff || (num == cutoff && c <= cutlim)) {
                    877:                                num = num * base + c;
                    878:                                break;
                    879:                        } else {
                    880:                                fnum = num;
                    881:                                mode = 1;
                    882:                        }
                    883:                        /* fall-through */
                    884:                case 1: /* Float */
                    885:                        fnum = fnum * base + c;
                    886:                }       
                    887:        }
                    888: 
                    889:        if (mode == 1) {
                    890:                ZVAL_DOUBLE(ret, fnum);
                    891:        } else {
                    892:                ZVAL_LONG(ret, num);
                    893:        }
                    894:        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: 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:        if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) {
                    911:                return STR_EMPTY_ALLOC();
                    912:        }
                    913: 
                    914:        value = Z_LVAL_P(arg);
                    915: 
                    916:        end = ptr = buf + sizeof(buf) - 1;
                    917:        *ptr = '\0';
                    918: 
                    919:        do {
                    920:                *--ptr = digits[value % base];
                    921:                value /= base;
                    922:        } while (ptr > buf && value);
                    923: 
                    924:        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: PHPAPI char * _php_math_zvaltobase(zval *arg, int base TSRMLS_DC)
                    934: {
                    935:        static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
                    936: 
                    937:        if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
                    938:                return STR_EMPTY_ALLOC();
                    939:        }
                    940: 
                    941:        if (Z_TYPE_P(arg) == IS_DOUBLE) {
                    942:                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:                if (fvalue == HUGE_VAL || fvalue == -HUGE_VAL) {
                    948:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number too large");
                    949:                        return STR_EMPTY_ALLOC();
                    950:                }
                    951: 
                    952:                end = ptr = buf + sizeof(buf) - 1;
                    953:                *ptr = '\0';
                    954: 
                    955:                do {
                    956:                        *--ptr = digits[(int) fmod(fvalue, base)];
                    957:                        fvalue /= base;
                    958:                } while (ptr > buf && fabs(fvalue) >= 1);
                    959: 
                    960:                return estrndup(ptr, end - ptr);
                    961:        }
                    962:        
                    963:        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: PHP_FUNCTION(bindec)
                    970: {
                    971:        zval **arg;
                    972:        
                    973:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                    974:                return;
                    975:        }
                    976:        convert_to_string_ex(arg);
                    977:        if (_php_math_basetozval(*arg, 2, return_value) == FAILURE) {
                    978:                RETURN_FALSE;
                    979:        }
                    980: }
                    981: /* }}} */
                    982: 
                    983: /* {{{ proto int hexdec(string hexadecimal_number)
                    984:    Returns the decimal equivalent of the hexadecimal number */
                    985: PHP_FUNCTION(hexdec)
                    986: {
                    987:        zval **arg;
                    988:        
                    989:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                    990:                return;
                    991:        }
                    992:        convert_to_string_ex(arg);
                    993:        if (_php_math_basetozval(*arg, 16, return_value) == FAILURE) {
                    994:                RETURN_FALSE;
                    995:        }
                    996: }
                    997: /* }}} */
                    998: 
                    999: /* {{{ proto int octdec(string octal_number)
                   1000:    Returns the decimal equivalent of an octal string */
                   1001: PHP_FUNCTION(octdec)
                   1002: {
                   1003:        zval **arg;
                   1004:        
                   1005:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                   1006:                return;
                   1007:        }
                   1008:        convert_to_string_ex(arg);
                   1009:        if (_php_math_basetozval(*arg, 8, return_value) == FAILURE) {
                   1010:                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: PHP_FUNCTION(decbin)
                   1018: {
                   1019:        zval **arg;
                   1020:        char *result;
                   1021: 
                   1022:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                   1023:                return;
                   1024:        }
                   1025:        convert_to_long_ex(arg);
                   1026:        result = _php_math_longtobase(*arg, 2);
                   1027:        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: PHP_FUNCTION(decoct)
                   1034: {
                   1035:        zval **arg;
                   1036:        char *result;
                   1037: 
                   1038:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                   1039:                return;
                   1040:        }
                   1041:        convert_to_long_ex(arg);
                   1042:        result = _php_math_longtobase(*arg, 8);
                   1043:        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: PHP_FUNCTION(dechex)
                   1050: {
                   1051:        zval **arg;
                   1052:        char *result;
                   1053: 
                   1054:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
                   1055:                return;
                   1056:        }
                   1057:        convert_to_long_ex(arg);
                   1058:        result = _php_math_longtobase(*arg, 16);
                   1059:        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: PHP_FUNCTION(base_convert)
                   1066: {
                   1067:        zval **number, temp;
                   1068:        long frombase, tobase;
                   1069:        char *result;
                   1070: 
                   1071:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zll", &number, &frombase, &tobase) == FAILURE) {
                   1072:                return;
                   1073:        }
                   1074:        convert_to_string_ex(number);
                   1075:        
                   1076:        if (frombase < 2 || frombase > 36) {
                   1077:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `from base' (%ld)", frombase);
                   1078:                RETURN_FALSE;
                   1079:        }
                   1080:        if (tobase < 2 || tobase > 36) {
                   1081:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `to base' (%ld)", tobase);
                   1082:                RETURN_FALSE;
                   1083:        }
                   1084: 
                   1085:        if(_php_math_basetozval(*number, frombase, &temp) == FAILURE) {
                   1086:                RETURN_FALSE;
                   1087:        }
                   1088:        result = _php_math_zvaltobase(&temp, tobase TSRMLS_CC);
                   1089:        RETVAL_STRING(result, 0);
                   1090: } 
                   1091: /* }}} */
                   1092: 
                   1093: /* {{{ _php_math_number_format 
                   1094: */
                   1095: PHPAPI char *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
                   1096: {
1.1.1.2   misho    1097:        return _php_math_number_format_ex(d, dec, &dec_point, 1, &thousand_sep, 1);
                   1098: }
                   1099: 
1.1.1.3   misho    1100: static char *_php_math_number_format_ex_len(double d, int dec, char *dec_point,
                   1101:                size_t dec_point_len, char *thousand_sep, size_t thousand_sep_len,
                   1102:                int *result_len)
1.1.1.2   misho    1103: {
1.1       misho    1104:        char *tmpbuf = NULL, *resbuf;
                   1105:        char *s, *t;  /* source, target */
                   1106:        char *dp;
                   1107:        int integral;
                   1108:        int tmplen, reslen=0;
                   1109:        int count=0;
                   1110:        int is_negative=0;
                   1111: 
                   1112:        if (d < 0) {
                   1113:                is_negative = 1;
                   1114:                d = -d;
                   1115:        }
                   1116: 
                   1117:        dec = MAX(0, dec);
                   1118:        d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);
                   1119: 
                   1120:        tmplen = spprintf(&tmpbuf, 0, "%.*F", dec, d);
                   1121: 
                   1122:        if (tmpbuf == NULL || !isdigit((int)tmpbuf[0])) {
1.1.1.3   misho    1123:                if (result_len) {
                   1124:                        *result_len = tmplen;
                   1125:                }
                   1126: 
1.1       misho    1127:                return tmpbuf;
                   1128:        }
                   1129: 
                   1130:        /* find decimal point, if expected */
                   1131:        if (dec) {
                   1132:                dp = strpbrk(tmpbuf, ".,");
                   1133:        } else {
                   1134:                dp = NULL;
                   1135:        }
                   1136: 
                   1137:        /* calculate the length of the return buffer */
                   1138:        if (dp) {
                   1139:                integral = dp - tmpbuf;
                   1140:        } else {
                   1141:                /* no decimal point was found */
                   1142:                integral = tmplen;
                   1143:        }
                   1144: 
                   1145:        /* allow for thousand separators */
                   1146:        if (thousand_sep) {
1.1.1.2   misho    1147:                integral += thousand_sep_len * ((integral-1) / 3);
1.1       misho    1148:        }
                   1149:        
                   1150:        reslen = integral;
                   1151:        
                   1152:        if (dec) {
                   1153:                reslen += dec;
                   1154: 
                   1155:                if (dec_point) {
1.1.1.2   misho    1156:                        reslen += dec_point_len;
1.1       misho    1157:                }
                   1158:        }
                   1159: 
                   1160:        /* add a byte for minus sign */
                   1161:        if (is_negative) {
                   1162:                reslen++;
                   1163:        }
                   1164:        resbuf = (char *) emalloc(reslen+1); /* +1 for NUL terminator */
                   1165: 
                   1166:        s = tmpbuf+tmplen-1;
                   1167:        t = resbuf+reslen;
                   1168:        *t-- = '\0';
                   1169: 
                   1170:        /* copy the decimal places.
                   1171:         * Take care, as the sprintf implementation may return less places than
                   1172:         * we requested due to internal buffer limitations */
                   1173:        if (dec) {
                   1174:                int declen = dp ? s - dp : 0;
                   1175:                int topad = dec > declen ? dec - declen : 0;
                   1176: 
                   1177:                /* pad with '0's */
                   1178:                while (topad--) {
                   1179:                        *t-- = '0';
                   1180:                }
                   1181:                
                   1182:                if (dp) {
                   1183:                        s -= declen + 1; /* +1 to skip the point */
                   1184:                        t -= declen;
                   1185: 
                   1186:                        /* now copy the chars after the point */
                   1187:                        memcpy(t + 1, dp + 1, declen);
                   1188:                }
                   1189: 
                   1190:                /* add decimal point */
                   1191:                if (dec_point) {
1.1.1.2   misho    1192:                        t -= dec_point_len;
                   1193:                        memcpy(t + 1, dec_point, dec_point_len);
1.1       misho    1194:                }
                   1195:        }
                   1196: 
                   1197:        /* copy the numbers before the decimal point, adding thousand
                   1198:         * separator every three digits */
                   1199:        while(s >= tmpbuf) {
                   1200:                *t-- = *s--;
                   1201:                if (thousand_sep && (++count%3)==0 && s>=tmpbuf) {
1.1.1.2   misho    1202:                        t -= thousand_sep_len;
                   1203:                        memcpy(t + 1, thousand_sep, thousand_sep_len);
1.1       misho    1204:                }
                   1205:        }
                   1206: 
                   1207:        /* and a minus sign, if needed */
                   1208:        if (is_negative) {
                   1209:                *t-- = '-';
                   1210:        }
                   1211: 
                   1212:        efree(tmpbuf);
                   1213:        
1.1.1.3   misho    1214:        if (result_len) {
                   1215:                *result_len = reslen;
                   1216:        }
                   1217: 
1.1       misho    1218:        return resbuf;
                   1219: }
1.1.1.3   misho    1220: 
                   1221: PHPAPI char *_php_math_number_format_ex(double d, int dec, char *dec_point,
                   1222:                size_t dec_point_len, char *thousand_sep, size_t thousand_sep_len)
                   1223: {
                   1224:        return _php_math_number_format_ex_len(d, dec, dec_point, dec_point_len,
                   1225:                        thousand_sep, thousand_sep_len, NULL);
                   1226: }
1.1       misho    1227: /* }}} */
                   1228: 
                   1229: /* {{{ proto string number_format(float number [, int num_decimal_places [, string dec_seperator, string thousands_seperator]])
                   1230:    Formats a number with grouped thousands */
                   1231: PHP_FUNCTION(number_format)
                   1232: {
                   1233:        double num;
                   1234:        long dec = 0;
                   1235:        char *thousand_sep = NULL, *dec_point = NULL;
                   1236:        char thousand_sep_chr = ',', dec_point_chr = '.';
                   1237:        int thousand_sep_len = 0, dec_point_len = 0;
                   1238:        
                   1239:        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) {
                   1240:                return;
                   1241:        }
                   1242: 
                   1243:        switch(ZEND_NUM_ARGS()) {
                   1244:        case 1:
                   1245:                RETURN_STRING(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr), 0);
                   1246:                break;
                   1247:        case 2:
                   1248:                RETURN_STRING(_php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr), 0);
                   1249:                break;
                   1250:        case 4:
1.1.1.2   misho    1251:                if (dec_point == NULL) {
                   1252:                        dec_point = &dec_point_chr;
                   1253:                        dec_point_len = 1;
1.1       misho    1254:                }
1.1.1.2   misho    1255: 
                   1256:                if (thousand_sep == NULL) {
                   1257:                        thousand_sep = &thousand_sep_chr;
                   1258:                        thousand_sep_len = 1;
1.1       misho    1259:                }
1.1.1.2   misho    1260: 
1.1.1.3   misho    1261:                Z_TYPE_P(return_value) = IS_STRING;
                   1262:                Z_STRVAL_P(return_value) = _php_math_number_format_ex_len(num, dec,
                   1263:                                dec_point, dec_point_len, thousand_sep, thousand_sep_len,
                   1264:                                &Z_STRLEN_P(return_value));
1.1       misho    1265:                break;
                   1266:        default:
                   1267:                WRONG_PARAM_COUNT;
                   1268:                break;
                   1269:        }
                   1270: }
                   1271: /* }}} */
                   1272: 
                   1273: /* {{{ proto float fmod(float x, float y)
                   1274:    Returns the remainder of dividing x by y as a float */
                   1275: PHP_FUNCTION(fmod)
                   1276: {
                   1277:        double num1, num2;
                   1278: 
                   1279:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd",  &num1, &num2) == FAILURE) {
                   1280:                return;
                   1281:        }
                   1282:        RETURN_DOUBLE(fmod(num1, num2));
                   1283: }
                   1284: /* }}} */
                   1285: 
                   1286: 
                   1287: 
                   1288: /*
                   1289:  * Local variables:
                   1290:  * tab-width: 4
                   1291:  * c-basic-offset: 4
                   1292:  * End:
                   1293:  * vim600: fdm=marker
                   1294:  * vim: noet sw=4 ts=4
                   1295:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>