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