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