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