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