1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Jim Winstead <jimw@php.net>                                 |
16   |          Stig Sæther Bakken <ssb@php.net>                            |
17   |          Zeev Suraski <zeev@zend.com>                                |
18   | PHP 4.0 patches by Thies C. Arntzen <thies@thieso.net>               |
19   +----------------------------------------------------------------------+
20*/
21
22/* $Id$ */
23
24#include "php.h"
25#include "php_math.h"
26#include "zend_multiply.h"
27
28#include <math.h>
29#include <float.h>
30#include <stdlib.h>
31
32#include "basic_functions.h"
33
34/* {{{ php_intlog10abs
35   Returns floor(log10(fabs(val))), uses fast binary search */
36static inline int php_intlog10abs(double value) {
37    int result;
38    value = fabs(value);
39
40    if (value < 1e-8 || value > 1e22) {
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 */
49        result = 15;
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 */
81static 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 */
96static 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 */
109static 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 */
139PHPAPI 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*/
217static 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*/
229static 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*/
241static 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*/
253static 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*/
265static 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 */
277PHP_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_P(value) == IS_DOUBLE) {
287        RETURN_DOUBLE(fabs(Z_DVAL_P(value)));
288    } else if (Z_TYPE_P(value) == IS_LONG) {
289        if (Z_LVAL_P(value) == ZEND_LONG_MIN) {
290            RETURN_DOUBLE(-(double)ZEND_LONG_MIN);
291        } else {
292            RETURN_LONG(Z_LVAL_P(value) < 0 ? -Z_LVAL_P(value) : Z_LVAL_P(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 */
301PHP_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_P(value) == IS_DOUBLE) {
311        RETURN_DOUBLE(ceil(Z_DVAL_P(value)));
312    } else if (Z_TYPE_P(value) == IS_LONG) {
313        RETURN_DOUBLE(zval_get_double(value));
314    }
315    RETURN_FALSE;
316}
317/* }}} */
318
319/* {{{ proto float floor(float number)
320   Returns the next lowest integer value from the number */
321PHP_FUNCTION(floor)
322{
323    zval *value;
324
325    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
326        return;
327    }
328    convert_scalar_to_number_ex(value);
329
330    if (Z_TYPE_P(value) == IS_DOUBLE) {
331        RETURN_DOUBLE(floor(Z_DVAL_P(value)));
332    } else if (Z_TYPE_P(value) == IS_LONG) {
333        RETURN_DOUBLE(zval_get_double(value));
334    }
335    RETURN_FALSE;
336}
337/* }}} */
338
339/* {{{ proto float round(float number [, int precision [, int mode]])
340   Returns the number rounded to specified precision */
341PHP_FUNCTION(round)
342{
343    zval *value;
344    int places = 0;
345    zend_long precision = 0;
346    zend_long mode = PHP_ROUND_HALF_UP;
347    double return_val;
348
349    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &value, &precision, &mode) == FAILURE) {
350        return;
351    }
352
353    if (ZEND_NUM_ARGS() >= 2) {
354        places = (int) precision;
355    }
356    convert_scalar_to_number_ex(value);
357
358    switch (Z_TYPE_P(value)) {
359        case IS_LONG:
360            /* Simple case - long that doesn't need to be rounded. */
361            if (places >= 0) {
362                RETURN_DOUBLE((double) Z_LVAL_P(value));
363            }
364            /* break omitted intentionally */
365
366        case IS_DOUBLE:
367            return_val = (Z_TYPE_P(value) == IS_LONG) ? (double)Z_LVAL_P(value) : Z_DVAL_P(value);
368            return_val = _php_math_round(return_val, places, mode);
369            RETURN_DOUBLE(return_val);
370            break;
371
372        default:
373            RETURN_FALSE;
374            break;
375    }
376}
377/* }}} */
378
379/* {{{ proto float sin(float number)
380   Returns the sine of the number in radians */
381PHP_FUNCTION(sin)
382{
383    double num;
384
385#ifndef FAST_ZPP
386    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
387        return;
388    }
389#else
390    ZEND_PARSE_PARAMETERS_START(1, 1)
391        Z_PARAM_DOUBLE(num)
392    ZEND_PARSE_PARAMETERS_END();
393#endif
394    RETURN_DOUBLE(sin(num));
395}
396/* }}} */
397
398/* {{{ proto float cos(float number)
399   Returns the cosine of the number in radians */
400PHP_FUNCTION(cos)
401{
402    double num;
403
404#ifndef FAST_ZPP
405    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
406        return;
407    }
408#else
409    ZEND_PARSE_PARAMETERS_START(1, 1)
410        Z_PARAM_DOUBLE(num)
411    ZEND_PARSE_PARAMETERS_END();
412#endif
413    RETURN_DOUBLE(cos(num));
414}
415/* }}} */
416
417/* {{{ proto float tan(float number)
418   Returns the tangent of the number in radians */
419PHP_FUNCTION(tan)
420{
421    double num;
422
423#ifndef FAST_ZPP
424    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
425        return;
426    }
427#else
428    ZEND_PARSE_PARAMETERS_START(1, 1)
429        Z_PARAM_DOUBLE(num)
430    ZEND_PARSE_PARAMETERS_END();
431#endif
432    RETURN_DOUBLE(tan(num));
433}
434/* }}} */
435
436/* {{{ proto float asin(float number)
437   Returns the arc sine of the number in radians */
438PHP_FUNCTION(asin)
439{
440    double num;
441
442#ifndef FAST_ZPP
443    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
444        return;
445    }
446#else
447    ZEND_PARSE_PARAMETERS_START(1, 1)
448        Z_PARAM_DOUBLE(num)
449    ZEND_PARSE_PARAMETERS_END();
450#endif
451    RETURN_DOUBLE(asin(num));
452}
453/* }}} */
454
455/* {{{ proto float acos(float number)
456   Return the arc cosine of the number in radians */
457PHP_FUNCTION(acos)
458{
459    double num;
460
461#ifndef FAST_ZPP
462    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
463        return;
464    }
465#else
466    ZEND_PARSE_PARAMETERS_START(1, 1)
467        Z_PARAM_DOUBLE(num)
468    ZEND_PARSE_PARAMETERS_END();
469#endif
470    RETURN_DOUBLE(acos(num));
471}
472/* }}} */
473
474/* {{{ proto float atan(float number)
475   Returns the arc tangent of the number in radians */
476PHP_FUNCTION(atan)
477{
478    double num;
479
480#ifndef FAST_ZPP
481    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
482        return;
483    }
484#else
485    ZEND_PARSE_PARAMETERS_START(1, 1)
486        Z_PARAM_DOUBLE(num)
487    ZEND_PARSE_PARAMETERS_END();
488#endif
489    RETURN_DOUBLE(atan(num));
490}
491/* }}} */
492
493/* {{{ proto float atan2(float y, float x)
494   Returns the arc tangent of y/x, with the resulting quadrant determined by the signs of y and x */
495PHP_FUNCTION(atan2)
496{
497    double num1, num2;
498
499#ifndef FAST_ZPP
500    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
501        return;
502    }
503#else
504    ZEND_PARSE_PARAMETERS_START(2, 2)
505        Z_PARAM_DOUBLE(num1)
506        Z_PARAM_DOUBLE(num2)
507    ZEND_PARSE_PARAMETERS_END();
508#endif
509    RETURN_DOUBLE(atan2(num1, num2));
510}
511/* }}} */
512
513/* {{{ proto float sinh(float number)
514   Returns the hyperbolic sine of the number, defined as (exp(number) - exp(-number))/2 */
515PHP_FUNCTION(sinh)
516{
517    double num;
518
519#ifndef FAST_ZPP
520    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
521        return;
522    }
523#else
524    ZEND_PARSE_PARAMETERS_START(1, 1)
525        Z_PARAM_DOUBLE(num)
526    ZEND_PARSE_PARAMETERS_END();
527#endif
528    RETURN_DOUBLE(sinh(num));
529}
530/* }}} */
531
532/* {{{ proto float cosh(float number)
533   Returns the hyperbolic cosine of the number, defined as (exp(number) + exp(-number))/2 */
534PHP_FUNCTION(cosh)
535{
536    double num;
537
538#ifndef FAST_ZPP
539    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
540        return;
541    }
542#else
543    ZEND_PARSE_PARAMETERS_START(1, 1)
544        Z_PARAM_DOUBLE(num)
545    ZEND_PARSE_PARAMETERS_END();
546#endif
547    RETURN_DOUBLE(cosh(num));
548}
549/* }}} */
550
551/* {{{ proto float tanh(float number)
552   Returns the hyperbolic tangent of the number, defined as sinh(number)/cosh(number) */
553PHP_FUNCTION(tanh)
554{
555    double num;
556
557#ifndef FAST_ZPP
558    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
559        return;
560    }
561#else
562    ZEND_PARSE_PARAMETERS_START(1, 1)
563        Z_PARAM_DOUBLE(num)
564    ZEND_PARSE_PARAMETERS_END();
565#endif
566    RETURN_DOUBLE(tanh(num));
567}
568/* }}} */
569
570/* {{{ proto float asinh(float number)
571   Returns the inverse hyperbolic sine of the number, i.e. the value whose hyperbolic sine is number */
572PHP_FUNCTION(asinh)
573{
574    double num;
575
576#ifndef FAST_ZPP
577    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
578        return;
579    }
580#else
581    ZEND_PARSE_PARAMETERS_START(1, 1)
582        Z_PARAM_DOUBLE(num)
583    ZEND_PARSE_PARAMETERS_END();
584#endif
585    RETURN_DOUBLE(php_asinh(num));
586}
587/* }}} */
588
589/* {{{ proto float acosh(float number)
590   Returns the inverse hyperbolic cosine of the number, i.e. the value whose hyperbolic cosine is number */
591PHP_FUNCTION(acosh)
592{
593    double num;
594
595#ifndef FAST_ZPP
596    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
597        return;
598    }
599#else
600    ZEND_PARSE_PARAMETERS_START(1, 1)
601        Z_PARAM_DOUBLE(num)
602    ZEND_PARSE_PARAMETERS_END();
603#endif
604    RETURN_DOUBLE(php_acosh(num));
605}
606/* }}} */
607
608/* {{{ proto float atanh(float number)
609   Returns the inverse hyperbolic tangent of the number, i.e. the value whose hyperbolic tangent is number */
610PHP_FUNCTION(atanh)
611{
612    double num;
613
614#ifndef FAST_ZPP
615    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
616        return;
617    }
618#else
619    ZEND_PARSE_PARAMETERS_START(1, 1)
620        Z_PARAM_DOUBLE(num)
621    ZEND_PARSE_PARAMETERS_END();
622#endif
623    RETURN_DOUBLE(php_atanh(num));
624}
625/* }}} */
626
627/* {{{ proto float pi(void)
628   Returns an approximation of pi */
629PHP_FUNCTION(pi)
630{
631    RETURN_DOUBLE(M_PI);
632}
633/* }}} */
634
635/* {{{ proto bool is_finite(float val)
636   Returns whether argument is finite */
637PHP_FUNCTION(is_finite)
638{
639    double dval;
640
641#ifndef FAST_ZPP
642    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
643        return;
644    }
645#else
646    ZEND_PARSE_PARAMETERS_START(1, 1)
647        Z_PARAM_DOUBLE(dval)
648    ZEND_PARSE_PARAMETERS_END();
649#endif
650    RETURN_BOOL(zend_finite(dval));
651}
652/* }}} */
653
654/* {{{ proto bool is_infinite(float val)
655   Returns whether argument is infinite */
656PHP_FUNCTION(is_infinite)
657{
658    double dval;
659
660#ifndef FAST_ZPP
661    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
662        return;
663    }
664#else
665    ZEND_PARSE_PARAMETERS_START(1, 1)
666        Z_PARAM_DOUBLE(dval)
667    ZEND_PARSE_PARAMETERS_END();
668#endif
669    RETURN_BOOL(zend_isinf(dval));
670}
671/* }}} */
672
673/* {{{ proto bool is_nan(float val)
674   Returns whether argument is not a number */
675PHP_FUNCTION(is_nan)
676{
677    double dval;
678
679#ifndef FAST_ZPP
680    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
681        return;
682    }
683#else
684    ZEND_PARSE_PARAMETERS_START(1, 1)
685        Z_PARAM_DOUBLE(dval)
686    ZEND_PARSE_PARAMETERS_END();
687#endif
688    RETURN_BOOL(zend_isnan(dval));
689}
690/* }}} */
691
692/* {{{ proto number pow(number base, number exponent)
693   Returns base raised to the power of exponent. Returns integer result when possible */
694PHP_FUNCTION(pow)
695{
696    zval *zbase, *zexp;
697
698    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/", &zbase, &zexp) == FAILURE) {
699        return;
700    }
701
702    pow_function(return_value, zbase, zexp TSRMLS_CC);
703}
704/* }}} */
705
706/* {{{ proto float exp(float number)
707   Returns e raised to the power of the number */
708PHP_FUNCTION(exp)
709{
710    double num;
711
712#ifndef FAST_ZPP
713    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
714        return;
715    }
716#else
717    ZEND_PARSE_PARAMETERS_START(1, 1)
718        Z_PARAM_DOUBLE(num)
719    ZEND_PARSE_PARAMETERS_END();
720#endif
721
722    RETURN_DOUBLE(exp(num));
723}
724/* }}} */
725
726/* {{{ proto float expm1(float number)
727   Returns exp(number) - 1, computed in a way that accurate even when the value of number is close to zero */
728/*
729   WARNING: this function is expermental: it could change its name or
730   disappear in the next version of PHP!
731*/
732PHP_FUNCTION(expm1)
733{
734    double num;
735
736#ifndef FAST_ZPP
737    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
738        return;
739    }
740#else
741    ZEND_PARSE_PARAMETERS_START(1, 1)
742        Z_PARAM_DOUBLE(num)
743    ZEND_PARSE_PARAMETERS_END();
744#endif
745
746    RETURN_DOUBLE(php_expm1(num));
747}
748/* }}} */
749
750/* {{{ proto float log1p(float number)
751   Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero */
752/*
753   WARNING: this function is expermental: it could change its name or
754   disappear in the next version of PHP!
755*/
756PHP_FUNCTION(log1p)
757{
758    double num;
759
760#ifndef FAST_ZPP
761    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
762        return;
763    }
764#else
765    ZEND_PARSE_PARAMETERS_START(1, 1)
766        Z_PARAM_DOUBLE(num)
767    ZEND_PARSE_PARAMETERS_END();
768#endif
769
770    RETURN_DOUBLE(php_log1p(num));
771}
772/* }}} */
773
774/* {{{ proto float log(float number, [float base])
775   Returns the natural logarithm of the number, or the base log if base is specified */
776PHP_FUNCTION(log)
777{
778    double num, base = 0;
779
780#ifndef FAST_ZPP
781    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d|d", &num, &base) == FAILURE) {
782        return;
783    }
784#else
785    ZEND_PARSE_PARAMETERS_START(1, 2)
786        Z_PARAM_DOUBLE(num)
787        Z_PARAM_OPTIONAL
788        Z_PARAM_DOUBLE(base)
789    ZEND_PARSE_PARAMETERS_END();
790#endif
791
792    if (ZEND_NUM_ARGS() == 1) {
793        RETURN_DOUBLE(log(num));
794    }
795
796#ifdef HAVE_LOG2
797    if (base == 2.0) {
798        RETURN_DOUBLE(log2(num));
799    }
800#endif
801
802    if (base == 10.0) {
803        RETURN_DOUBLE(log10(num));
804    }
805
806    if (base == 1.0) {
807        RETURN_DOUBLE(php_get_nan());
808    }
809
810    if (base <= 0.0) {
811        php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0");
812        RETURN_FALSE;
813    }
814
815    RETURN_DOUBLE(log(num) / log(base));
816}
817/* }}} */
818
819/* {{{ proto float log10(float number)
820   Returns the base-10 logarithm of the number */
821PHP_FUNCTION(log10)
822{
823    double num;
824
825#ifndef FAST_ZPP
826    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
827        return;
828    }
829#else
830    ZEND_PARSE_PARAMETERS_START(1, 1)
831        Z_PARAM_DOUBLE(num)
832    ZEND_PARSE_PARAMETERS_END();
833#endif
834
835    RETURN_DOUBLE(log10(num));
836}
837/* }}} */
838
839/* {{{ proto float sqrt(float number)
840   Returns the square root of the number */
841PHP_FUNCTION(sqrt)
842{
843    double num;
844
845#ifndef FAST_ZPP
846    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &num) == FAILURE) {
847        return;
848    }
849#else
850    ZEND_PARSE_PARAMETERS_START(1, 1)
851        Z_PARAM_DOUBLE(num)
852    ZEND_PARSE_PARAMETERS_END();
853#endif
854
855    RETURN_DOUBLE(sqrt(num));
856}
857/* }}} */
858
859/* {{{ proto float hypot(float num1, float num2)
860   Returns sqrt(num1*num1 + num2*num2) */
861PHP_FUNCTION(hypot)
862{
863    double num1, num2;
864
865#ifndef FAST_ZPP
866    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
867        return;
868    }
869#else
870    ZEND_PARSE_PARAMETERS_START(2, 2)
871        Z_PARAM_DOUBLE(num1)
872        Z_PARAM_DOUBLE(num2)
873    ZEND_PARSE_PARAMETERS_END();
874#endif
875
876#if HAVE_HYPOT
877    RETURN_DOUBLE(hypot(num1, num2));
878#elif defined(_MSC_VER)
879    RETURN_DOUBLE(_hypot(num1, num2));
880#else
881    RETURN_DOUBLE(sqrt((num1 * num1) + (num2 * num2)));
882#endif
883}
884/* }}} */
885
886/* {{{ proto float deg2rad(float number)
887   Converts the number in degrees to the radian equivalent */
888PHP_FUNCTION(deg2rad)
889{
890    double deg;
891
892#ifndef FAST_ZPP
893    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &deg) == FAILURE) {
894        return;
895    }
896#else
897    ZEND_PARSE_PARAMETERS_START(1, 1)
898        Z_PARAM_DOUBLE(deg)
899    ZEND_PARSE_PARAMETERS_END();
900#endif
901    RETURN_DOUBLE((deg / 180.0) * M_PI);
902}
903/* }}} */
904
905/* {{{ proto float rad2deg(float number)
906   Converts the radian number to the equivalent number in degrees */
907PHP_FUNCTION(rad2deg)
908{
909    double rad;
910
911#ifndef FAST_ZPP
912    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &rad) == FAILURE) {
913        return;
914    }
915#else
916    ZEND_PARSE_PARAMETERS_START(1, 1)
917        Z_PARAM_DOUBLE(rad)
918    ZEND_PARSE_PARAMETERS_END();
919#endif
920
921    RETURN_DOUBLE((rad / M_PI) * 180);
922}
923/* }}} */
924
925/* {{{ _php_math_basetolong */
926/*
927 * Convert a string representation of a base(2-36) number to a long.
928 */
929PHPAPI zend_long _php_math_basetolong(zval *arg, int base)
930{
931    zend_long num = 0, digit, onum;
932    int i;
933    char c, *s;
934
935    if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
936        return 0;
937    }
938
939    s = Z_STRVAL_P(arg);
940
941    for (i = Z_STRLEN_P(arg); i > 0; i--) {
942        c = *s++;
943
944        digit = (c >= '0' && c <= '9') ? c - '0'
945            : (c >= 'A' && c <= 'Z') ? c - 'A' + 10
946            : (c >= 'a' && c <= 'z') ? c - 'a' + 10
947            : base;
948
949        if (digit >= base) {
950            continue;
951        }
952
953        onum = num;
954        num = num * base + digit;
955        if (num > onum)
956            continue;
957
958        {
959            TSRMLS_FETCH();
960
961            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number '%s' is too big to fit in long", s);
962            return ZEND_LONG_MAX;
963        }
964    }
965
966    return num;
967}
968/* }}} */
969
970/* {{{ _php_math_basetozval */
971/*
972 * Convert a string representation of a base(2-36) number to a zval.
973 */
974PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret)
975{
976    zend_long num = 0;
977    double fnum = 0;
978    int i;
979    int mode = 0;
980    char c, *s;
981    zend_long cutoff;
982    int cutlim;
983
984    if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
985        return FAILURE;
986    }
987
988    s = Z_STRVAL_P(arg);
989
990    cutoff = ZEND_LONG_MAX / base;
991    cutlim = ZEND_LONG_MAX % base;
992
993    for (i = Z_STRLEN_P(arg); i > 0; i--) {
994        c = *s++;
995
996        /* might not work for EBCDIC */
997        if (c >= '0' && c <= '9')
998            c -= '0';
999        else if (c >= 'A' && c <= 'Z')
1000            c -= 'A' - 10;
1001        else if (c >= 'a' && c <= 'z')
1002            c -= 'a' - 10;
1003        else
1004            continue;
1005
1006        if (c >= base)
1007            continue;
1008
1009        switch (mode) {
1010        case 0: /* Integer */
1011            if (num < cutoff || (num == cutoff && c <= cutlim)) {
1012                num = num * base + c;
1013                break;
1014            } else {
1015                fnum = num;
1016                mode = 1;
1017            }
1018            /* fall-through */
1019        case 1: /* Float */
1020            fnum = fnum * base + c;
1021        }
1022    }
1023
1024    if (mode == 1) {
1025        ZVAL_DOUBLE(ret, fnum);
1026    } else {
1027        ZVAL_LONG(ret, num);
1028    }
1029    return SUCCESS;
1030}
1031/* }}} */
1032
1033/* {{{ _php_math_longtobase */
1034/*
1035 * Convert a long to a string containing a base(2-36) representation of
1036 * the number.
1037 */
1038PHPAPI zend_string * _php_math_longtobase(zval *arg, int base TSRMLS_DC)
1039{
1040    static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1041    char buf[(sizeof(zend_ulong) << 3) + 1];
1042    char *ptr, *end;
1043    zend_ulong value;
1044
1045    if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) {
1046        return STR_EMPTY_ALLOC();
1047    }
1048
1049    value = Z_LVAL_P(arg);
1050
1051    end = ptr = buf + sizeof(buf) - 1;
1052    *ptr = '\0';
1053
1054    do {
1055        *--ptr = digits[value % base];
1056        value /= base;
1057    } while (ptr > buf && value);
1058
1059    return zend_string_init(ptr, end - ptr, 0);
1060}
1061/* }}} */
1062
1063/* {{{ _php_math_zvaltobase */
1064/*
1065 * Convert a zval to a string containing a base(2-36) representation of
1066 * the number.
1067 */
1068PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base TSRMLS_DC)
1069{
1070    static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
1071
1072    if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
1073        return STR_EMPTY_ALLOC();
1074    }
1075
1076    if (Z_TYPE_P(arg) == IS_DOUBLE) {
1077        double fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
1078        char *ptr, *end;
1079        char buf[(sizeof(double) << 3) + 1];
1080
1081        /* Don't try to convert +/- infinity */
1082        if (fvalue == HUGE_VAL || fvalue == -HUGE_VAL) {
1083            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number too large");
1084            return STR_EMPTY_ALLOC();
1085        }
1086
1087        end = ptr = buf + sizeof(buf) - 1;
1088        *ptr = '\0';
1089
1090        do {
1091            *--ptr = digits[(int) fmod(fvalue, base)];
1092            fvalue /= base;
1093        } while (ptr > buf && fabs(fvalue) >= 1);
1094
1095        return zend_string_init(ptr, end - ptr, 0);
1096    }
1097
1098    return _php_math_longtobase(arg, base TSRMLS_CC);
1099}
1100/* }}} */
1101
1102/* {{{ proto int bindec(string binary_number)
1103   Returns the decimal equivalent of the binary number */
1104PHP_FUNCTION(bindec)
1105{
1106    zval *arg;
1107
1108    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1109        return;
1110    }
1111    convert_to_string_ex(arg);
1112    if (_php_math_basetozval(arg, 2, return_value) == FAILURE) {
1113        RETURN_FALSE;
1114    }
1115}
1116/* }}} */
1117
1118/* {{{ proto int hexdec(string hexadecimal_number)
1119   Returns the decimal equivalent of the hexadecimal number */
1120PHP_FUNCTION(hexdec)
1121{
1122    zval *arg;
1123
1124    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1125        return;
1126    }
1127    convert_to_string_ex(arg);
1128    if (_php_math_basetozval(arg, 16, return_value) == FAILURE) {
1129        RETURN_FALSE;
1130    }
1131}
1132/* }}} */
1133
1134/* {{{ proto int octdec(string octal_number)
1135   Returns the decimal equivalent of an octal string */
1136PHP_FUNCTION(octdec)
1137{
1138    zval *arg;
1139
1140    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1141        return;
1142    }
1143    convert_to_string_ex(arg);
1144    if (_php_math_basetozval(arg, 8, return_value) == FAILURE) {
1145        RETURN_FALSE;
1146    }
1147}
1148/* }}} */
1149
1150/* {{{ proto string decbin(int decimal_number)
1151   Returns a string containing a binary representation of the number */
1152PHP_FUNCTION(decbin)
1153{
1154    zval *arg;
1155    zend_string *result;
1156
1157    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1158        return;
1159    }
1160    convert_to_long_ex(arg);
1161    result = _php_math_longtobase(arg, 2 TSRMLS_CC);
1162    RETURN_STR(result);
1163}
1164/* }}} */
1165
1166/* {{{ proto string decoct(int decimal_number)
1167   Returns a string containing an octal representation of the given number */
1168PHP_FUNCTION(decoct)
1169{
1170    zval *arg;
1171    zend_string *result;
1172
1173    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1174        return;
1175    }
1176    convert_to_long_ex(arg);
1177    result = _php_math_longtobase(arg, 8 TSRMLS_CC);
1178    RETURN_STR(result);
1179}
1180/* }}} */
1181
1182/* {{{ proto string dechex(int decimal_number)
1183   Returns a string containing a hexadecimal representation of the given number */
1184PHP_FUNCTION(dechex)
1185{
1186    zval *arg;
1187    zend_string *result;
1188
1189    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &arg) == FAILURE) {
1190        return;
1191    }
1192    convert_to_long_ex(arg);
1193    result = _php_math_longtobase(arg, 16 TSRMLS_CC);
1194    RETURN_STR(result);
1195}
1196/* }}} */
1197
1198/* {{{ proto string base_convert(string number, int frombase, int tobase)
1199   Converts a number in a string from any base <= 36 to any base <= 36 */
1200PHP_FUNCTION(base_convert)
1201{
1202    zval *number, temp;
1203    zend_long frombase, tobase;
1204    zend_string *result;
1205
1206    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zll", &number, &frombase, &tobase) == FAILURE) {
1207        return;
1208    }
1209    convert_to_string_ex(number);
1210
1211    if (frombase < 2 || frombase > 36) {
1212        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `from base' (%pd)", frombase);
1213        RETURN_FALSE;
1214    }
1215    if (tobase < 2 || tobase > 36) {
1216        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `to base' (%pd)", tobase);
1217        RETURN_FALSE;
1218    }
1219
1220    if(_php_math_basetozval(number, frombase, &temp) == FAILURE) {
1221        RETURN_FALSE;
1222    }
1223    result = _php_math_zvaltobase(&temp, tobase TSRMLS_CC);
1224    RETVAL_STR(result);
1225}
1226/* }}} */
1227
1228/* {{{ _php_math_number_format
1229*/
1230PHPAPI zend_string *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
1231{
1232    return _php_math_number_format_ex(d, dec, &dec_point, 1, &thousand_sep, 1);
1233}
1234
1235PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, char *dec_point,
1236        size_t dec_point_len, char *thousand_sep, size_t thousand_sep_len)
1237{
1238    zend_string *res;
1239    zend_string *tmpbuf;
1240    char *s, *t;  /* source, target */
1241    char *dp;
1242    int integral;
1243    int reslen = 0;
1244    int count = 0;
1245    int is_negative=0;
1246
1247    if (d < 0) {
1248        is_negative = 1;
1249        d = -d;
1250    }
1251
1252    dec = MAX(0, dec);
1253    d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);
1254    tmpbuf = strpprintf(0, "%.*F", dec, d);
1255    if (tmpbuf == NULL) {
1256        return NULL;
1257    } else if (!isdigit((int)tmpbuf->val[0])) {
1258        return tmpbuf;
1259    }
1260
1261    /* find decimal point, if expected */
1262    if (dec) {
1263        dp = strpbrk(tmpbuf->val, ".,");
1264    } else {
1265        dp = NULL;
1266    }
1267
1268    /* calculate the length of the return buffer */
1269    if (dp) {
1270        integral = dp - tmpbuf->val;
1271    } else {
1272        /* no decimal point was found */
1273        integral = tmpbuf->len;
1274    }
1275
1276    /* allow for thousand separators */
1277    if (thousand_sep) {
1278        integral += thousand_sep_len * ((integral-1) / 3);
1279    }
1280
1281    reslen = integral;
1282
1283    if (dec) {
1284        reslen += dec;
1285
1286        if (dec_point) {
1287            reslen += dec_point_len;
1288        }
1289    }
1290
1291    /* add a byte for minus sign */
1292    if (is_negative) {
1293        reslen++;
1294    }
1295    res = zend_string_alloc(reslen, 0);
1296
1297    s = tmpbuf->val + tmpbuf->len - 1;
1298    t = res->val + reslen;
1299    *t-- = '\0';
1300
1301    /* copy the decimal places.
1302     * Take care, as the sprintf implementation may return less places than
1303     * we requested due to internal buffer limitations */
1304    if (dec) {
1305        int declen = dp ? s - dp : 0;
1306        int topad = dec > declen ? dec - declen : 0;
1307
1308        /* pad with '0's */
1309        while (topad--) {
1310            *t-- = '0';
1311        }
1312
1313        if (dp) {
1314            s -= declen + 1; /* +1 to skip the point */
1315            t -= declen;
1316
1317            /* now copy the chars after the point */
1318            memcpy(t + 1, dp + 1, declen);
1319        }
1320
1321        /* add decimal point */
1322        if (dec_point) {
1323            t -= dec_point_len;
1324            memcpy(t + 1, dec_point, dec_point_len);
1325        }
1326    }
1327
1328    /* copy the numbers before the decimal point, adding thousand
1329     * separator every three digits */
1330    while (s >= tmpbuf->val) {
1331        *t-- = *s--;
1332        if (thousand_sep && (++count%3)==0 && s>=tmpbuf->val) {
1333            t -= thousand_sep_len;
1334            memcpy(t + 1, thousand_sep, thousand_sep_len);
1335        }
1336    }
1337
1338    /* and a minus sign, if needed */
1339    if (is_negative) {
1340        *t-- = '-';
1341    }
1342
1343    res->len = reslen;
1344    zend_string_release(tmpbuf);
1345    return res;
1346}
1347
1348/* {{{ proto string number_format(float number [, int num_decimal_places [, string dec_separator, string thousands_separator]])
1349   Formats a number with grouped thousands */
1350PHP_FUNCTION(number_format)
1351{
1352    double num;
1353    zend_long dec = 0;
1354    char *thousand_sep = NULL, *dec_point = NULL;
1355    char thousand_sep_chr = ',', dec_point_chr = '.';
1356    size_t thousand_sep_len = 0, dec_point_len = 0;
1357
1358#ifndef FAST_ZPP
1359    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) {
1360        return;
1361    }
1362#else
1363    ZEND_PARSE_PARAMETERS_START(1, 4)
1364        Z_PARAM_DOUBLE(num)
1365        Z_PARAM_OPTIONAL
1366        Z_PARAM_LONG(dec)
1367        Z_PARAM_STRING_EX(dec_point, dec_point_len, 1, 0)
1368        Z_PARAM_STRING_EX(thousand_sep, thousand_sep_len, 1, 0)
1369    ZEND_PARSE_PARAMETERS_END();
1370#endif
1371
1372    switch(ZEND_NUM_ARGS()) {
1373    case 1:
1374        RETURN_STR(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr));
1375        break;
1376    case 2:
1377        RETURN_STR(_php_math_number_format(num, dec, dec_point_chr, thousand_sep_chr));
1378        break;
1379    case 4:
1380        if (dec_point == NULL) {
1381            dec_point = &dec_point_chr;
1382            dec_point_len = 1;
1383        }
1384
1385        if (thousand_sep == NULL) {
1386            thousand_sep = &thousand_sep_chr;
1387            thousand_sep_len = 1;
1388        }
1389
1390        RETVAL_STR(_php_math_number_format_ex(num, dec,
1391                dec_point, dec_point_len, thousand_sep, thousand_sep_len));
1392        break;
1393    default:
1394        WRONG_PARAM_COUNT;
1395        break;
1396    }
1397}
1398/* }}} */
1399
1400/* {{{ proto float fmod(float x, float y)
1401   Returns the remainder of dividing x by y as a float */
1402PHP_FUNCTION(fmod)
1403{
1404    double num1, num2;
1405
1406#ifndef FAST_ZPP
1407    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd",  &num1, &num2) == FAILURE) {
1408        return;
1409    }
1410#else
1411    ZEND_PARSE_PARAMETERS_START(2, 2)
1412        Z_PARAM_DOUBLE(num1)
1413        Z_PARAM_DOUBLE(num2)
1414    ZEND_PARSE_PARAMETERS_END();
1415#endif
1416
1417    RETURN_DOUBLE(fmod(num1, num2));
1418}
1419/* }}} */
1420
1421/* {{{ proto int intdiv(int numerator, int divisor)
1422   Returns the integer division of the numerator by the divisor */
1423PHP_FUNCTION(intdiv)
1424{
1425    zend_long numerator, divisor;
1426
1427    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &numerator, &divisor) == FAILURE) {
1428        return;
1429    }
1430
1431    if (divisor == 0) {
1432        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
1433        RETURN_BOOL(0);
1434    } else if (divisor == -1 && numerator == ZEND_LONG_MIN) {
1435        /* Prevent overflow error/crash
1436           We don't return a float here as that violates function contract */
1437        RETURN_LONG(0);
1438    }
1439
1440    RETURN_LONG(numerator/divisor);
1441}
1442/* }}} */
1443
1444/*
1445 * Local variables:
1446 * tab-width: 4
1447 * c-basic-offset: 4
1448 * End:
1449 * vim600: fdm=marker
1450 * vim: noet sw=4 ts=4
1451 */
1452