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