mirror of
https://github.com/php/php-src.git
synced 2025-08-17 22:48:57 +02:00

This patch removes the so called local variables defined per file basis for certain editors to properly show tab width, and similar settings. These are mainly used by Vim and Emacs editors yet with recent changes the once working definitions don't work anymore in Vim without custom plugins or additional configuration. Neither are these settings synced across the PHP code base. A simpler and better approach is EditorConfig and fixing code using some code style fixing tools in the future instead. This patch also removes the so called modelines for Vim. Modelines allow Vim editor specifically to set some editor configuration such as syntax highlighting, indentation style and tab width to be set in the first line or the last 5 lines per file basis. Since the php test files have syntax highlighting already set in most editors properly and EditorConfig takes care of the indentation settings, this patch removes these as well for the Vim 6.0 and newer versions. With the removal of local variables for certain editors such as Emacs and Vim, the footer is also probably not needed anymore when creating extensions using ext_skel.php script. Additionally, Vim modelines for setting php syntax and some editor settings has been removed from some *.phpt files. All these are mostly not relevant for phpt files neither work properly in the middle of the file.
1320 lines
30 KiB
C
1320 lines
30 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| PHP Version 7 |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Authors: Jim Winstead <jimw@php.net> |
|
|
| Stig Sæther Bakken <ssb@php.net> |
|
|
| Zeev Suraski <zeev@php.net> |
|
|
| PHP 4.0 patches by Thies C. Arntzen <thies@thieso.net> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include "php.h"
|
|
#include "php_math.h"
|
|
#include "zend_multiply.h"
|
|
#include "zend_exceptions.h"
|
|
#include "zend_portability.h"
|
|
|
|
#include <math.h>
|
|
#include <float.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "basic_functions.h"
|
|
|
|
/* {{{ php_intlog10abs
|
|
Returns floor(log10(fabs(val))), uses fast binary search */
|
|
static inline int php_intlog10abs(double value) {
|
|
int result;
|
|
value = fabs(value);
|
|
|
|
if (value < 1e-8 || value > 1e22) {
|
|
result = (int)floor(log10(value));
|
|
} else {
|
|
static const double values[] = {
|
|
1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
|
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
|
|
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
|
|
/* Do a binary search with 5 steps */
|
|
result = 15;
|
|
if (value < values[result]) {
|
|
result -= 8;
|
|
} else {
|
|
result += 8;
|
|
}
|
|
if (value < values[result]) {
|
|
result -= 4;
|
|
} else {
|
|
result += 4;
|
|
}
|
|
if (value < values[result]) {
|
|
result -= 2;
|
|
} else {
|
|
result += 2;
|
|
}
|
|
if (value < values[result]) {
|
|
result -= 1;
|
|
} else {
|
|
result += 1;
|
|
}
|
|
if (value < values[result]) {
|
|
result -= 1;
|
|
}
|
|
result -= 8;
|
|
}
|
|
return result;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_intpow10
|
|
Returns pow(10.0, (double)power), uses fast lookup table for exact powers */
|
|
static inline double php_intpow10(int power) {
|
|
static const double powers[] = {
|
|
1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
|
|
1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
|
|
1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
|
|
|
|
/* Not in lookup table */
|
|
if (power < 0 || power > 22) {
|
|
return pow(10.0, (double)power);
|
|
}
|
|
return powers[power];
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_round_helper
|
|
Actually performs the rounding of a value to integer in a certain mode */
|
|
static inline double php_round_helper(double value, int mode) {
|
|
double tmp_value;
|
|
|
|
if (value >= 0.0) {
|
|
tmp_value = floor(value + 0.5);
|
|
if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) ||
|
|
(mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) ||
|
|
(mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)))
|
|
{
|
|
tmp_value = tmp_value - 1.0;
|
|
}
|
|
} else {
|
|
tmp_value = ceil(value - 0.5);
|
|
if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) ||
|
|
(mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) ||
|
|
(mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0)))
|
|
{
|
|
tmp_value = tmp_value + 1.0;
|
|
}
|
|
}
|
|
|
|
return tmp_value;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_math_round */
|
|
/*
|
|
* Rounds a number to a certain number of decimal places in a certain rounding
|
|
* mode. For the specifics of the algorithm, see http://wiki.php.net/rfc/rounding
|
|
*/
|
|
PHPAPI double _php_math_round(double value, int places, int mode) {
|
|
double f1, f2;
|
|
double tmp_value;
|
|
int precision_places;
|
|
|
|
if (!zend_finite(value)) {
|
|
return value;
|
|
}
|
|
|
|
places = places < INT_MIN+1 ? INT_MIN+1 : places;
|
|
precision_places = 14 - php_intlog10abs(value);
|
|
|
|
f1 = php_intpow10(abs(places));
|
|
|
|
/* If the decimal precision guaranteed by FP arithmetic is higher than
|
|
the requested places BUT is small enough to make sure a non-zero value
|
|
is returned, pre-round the result to the precision */
|
|
if (precision_places > places && precision_places - places < 15) {
|
|
int64_t use_precision = precision_places < INT_MIN+1 ? INT_MIN+1 : precision_places;
|
|
|
|
f2 = php_intpow10(abs((int)use_precision));
|
|
if (use_precision >= 0) {
|
|
tmp_value = value * f2;
|
|
} else {
|
|
tmp_value = value / f2;
|
|
}
|
|
/* preround the result (tmp_value will always be something * 1e14,
|
|
thus never larger than 1e15 here) */
|
|
tmp_value = php_round_helper(tmp_value, mode);
|
|
|
|
use_precision = places - precision_places;
|
|
use_precision = use_precision < INT_MIN+1 ? INT_MIN+1 : use_precision;
|
|
/* now correctly move the decimal point */
|
|
f2 = php_intpow10(abs((int)use_precision));
|
|
/* because places < precision_places */
|
|
tmp_value = tmp_value / f2;
|
|
} else {
|
|
/* adjust the value */
|
|
if (places >= 0) {
|
|
tmp_value = value * f1;
|
|
} else {
|
|
tmp_value = value / f1;
|
|
}
|
|
/* This value is beyond our precision, so rounding it is pointless */
|
|
if (fabs(tmp_value) >= 1e15) {
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/* round the temp value */
|
|
tmp_value = php_round_helper(tmp_value, mode);
|
|
|
|
/* see if it makes sense to use simple division to round the value */
|
|
if (abs(places) < 23) {
|
|
if (places > 0) {
|
|
tmp_value = tmp_value / f1;
|
|
} else {
|
|
tmp_value = tmp_value * f1;
|
|
}
|
|
} else {
|
|
/* Simple division can't be used since that will cause wrong results.
|
|
Instead, the number is converted to a string and back again using
|
|
strtod(). strtod() will return the nearest possible FP value for
|
|
that string. */
|
|
|
|
/* 40 Bytes should be more than enough for this format string. The
|
|
float won't be larger than 1e15 anyway. But just in case, use
|
|
snprintf() and make sure the buffer is zero-terminated */
|
|
char buf[40];
|
|
snprintf(buf, 39, "%15fe%d", tmp_value, -places);
|
|
buf[39] = '\0';
|
|
tmp_value = zend_strtod(buf, NULL);
|
|
/* couldn't convert to string and back */
|
|
if (!zend_finite(tmp_value) || zend_isnan(tmp_value)) {
|
|
tmp_value = value;
|
|
}
|
|
}
|
|
|
|
return tmp_value;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_asinh
|
|
*/
|
|
static double php_asinh(double z)
|
|
{
|
|
#ifdef HAVE_ASINH
|
|
return(asinh(z));
|
|
#else
|
|
# ifdef _WIN64
|
|
if (z >= 0) {
|
|
return log(z + sqrt(z * z + 1));
|
|
}
|
|
else {
|
|
return -log(-z + sqrt(z * z + 1));
|
|
}
|
|
# else
|
|
return(log(z + sqrt(1 + pow(z, 2))) / log(M_E));
|
|
# endif
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_acosh
|
|
*/
|
|
static double php_acosh(double x)
|
|
{
|
|
#ifdef HAVE_ACOSH
|
|
return(acosh(x));
|
|
#else
|
|
# ifdef _WIN64
|
|
if (x >= 1) {
|
|
return log(x + sqrt(x * x - 1));
|
|
} else {
|
|
return ZEND_NAN;
|
|
}
|
|
# else
|
|
return(log(x + sqrt(x * x - 1)));
|
|
# endif
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_atanh
|
|
*/
|
|
static double php_atanh(double z)
|
|
{
|
|
#ifdef HAVE_ATANH
|
|
return(atanh(z));
|
|
#else
|
|
return(0.5 * log((1 + z) / (1 - z)));
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_log1p
|
|
*/
|
|
static double php_log1p(double x)
|
|
{
|
|
#ifdef HAVE_LOG1P
|
|
return(log1p(x));
|
|
#else
|
|
return(log(1 + x));
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ php_expm1
|
|
*/
|
|
static double php_expm1(double x)
|
|
{
|
|
#ifndef PHP_WIN32
|
|
return(expm1(x));
|
|
#else
|
|
return(exp(x) - 1);
|
|
#endif
|
|
}
|
|
/* }}}*/
|
|
|
|
/* {{{ proto int abs(int number)
|
|
Return the absolute value of the number */
|
|
PHP_FUNCTION(abs)
|
|
{
|
|
zval *value;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(value)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_scalar_to_number_ex(value);
|
|
|
|
if (Z_TYPE_P(value) == IS_DOUBLE) {
|
|
RETURN_DOUBLE(fabs(Z_DVAL_P(value)));
|
|
} else if (Z_TYPE_P(value) == IS_LONG) {
|
|
if (Z_LVAL_P(value) == ZEND_LONG_MIN) {
|
|
RETURN_DOUBLE(-(double)ZEND_LONG_MIN);
|
|
} else {
|
|
RETURN_LONG(Z_LVAL_P(value) < 0 ? -Z_LVAL_P(value) : Z_LVAL_P(value));
|
|
}
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float ceil(float number)
|
|
Returns the next highest integer value of the number */
|
|
PHP_FUNCTION(ceil)
|
|
{
|
|
zval *value;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(value)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_scalar_to_number_ex(value);
|
|
|
|
if (Z_TYPE_P(value) == IS_DOUBLE) {
|
|
RETURN_DOUBLE(ceil(Z_DVAL_P(value)));
|
|
} else if (Z_TYPE_P(value) == IS_LONG) {
|
|
RETURN_DOUBLE(zval_get_double(value));
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float floor(float number)
|
|
Returns the next lowest integer value from the number */
|
|
PHP_FUNCTION(floor)
|
|
{
|
|
zval *value;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(value)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_scalar_to_number_ex(value);
|
|
|
|
if (Z_TYPE_P(value) == IS_DOUBLE) {
|
|
RETURN_DOUBLE(floor(Z_DVAL_P(value)));
|
|
} else if (Z_TYPE_P(value) == IS_LONG) {
|
|
RETURN_DOUBLE(zval_get_double(value));
|
|
}
|
|
RETURN_FALSE;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float round(float number [, int precision [, int mode]])
|
|
Returns the number rounded to specified precision */
|
|
PHP_FUNCTION(round)
|
|
{
|
|
zval *value;
|
|
int places = 0;
|
|
zend_long precision = 0;
|
|
zend_long mode = PHP_ROUND_HALF_UP;
|
|
double return_val;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 3)
|
|
Z_PARAM_ZVAL(value)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_LONG(precision)
|
|
Z_PARAM_LONG(mode)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (ZEND_NUM_ARGS() >= 2) {
|
|
#if SIZEOF_ZEND_LONG > SIZEOF_INT
|
|
if (precision >= 0) {
|
|
places = precision > INT_MAX ? INT_MAX : (int)precision;
|
|
} else {
|
|
places = precision <= INT_MIN ? INT_MIN+1 : (int)precision;
|
|
}
|
|
#else
|
|
places = precision;
|
|
#endif
|
|
}
|
|
convert_scalar_to_number_ex(value);
|
|
|
|
switch (Z_TYPE_P(value)) {
|
|
case IS_LONG:
|
|
/* Simple case - long that doesn't need to be rounded. */
|
|
if (places >= 0) {
|
|
RETURN_DOUBLE((double) Z_LVAL_P(value));
|
|
}
|
|
/* break omitted intentionally */
|
|
|
|
case IS_DOUBLE:
|
|
return_val = (Z_TYPE_P(value) == IS_LONG) ? (double)Z_LVAL_P(value) : Z_DVAL_P(value);
|
|
return_val = _php_math_round(return_val, (int)places, (int)mode);
|
|
RETURN_DOUBLE(return_val);
|
|
break;
|
|
|
|
default:
|
|
RETURN_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float sin(float number)
|
|
Returns the sine of the number in radians */
|
|
PHP_FUNCTION(sin)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(sin(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float cos(float number)
|
|
Returns the cosine of the number in radians */
|
|
PHP_FUNCTION(cos)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(cos(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float tan(float number)
|
|
Returns the tangent of the number in radians */
|
|
PHP_FUNCTION(tan)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(tan(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float asin(float number)
|
|
Returns the arc sine of the number in radians */
|
|
PHP_FUNCTION(asin)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(asin(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float acos(float number)
|
|
Return the arc cosine of the number in radians */
|
|
PHP_FUNCTION(acos)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(acos(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float atan(float number)
|
|
Returns the arc tangent of the number in radians */
|
|
PHP_FUNCTION(atan)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(atan(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float atan2(float y, float x)
|
|
Returns the arc tangent of y/x, with the resulting quadrant determined by the signs of y and x */
|
|
PHP_FUNCTION(atan2)
|
|
{
|
|
double num1, num2;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
Z_PARAM_DOUBLE(num1)
|
|
Z_PARAM_DOUBLE(num2)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(atan2(num1, num2));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float sinh(float number)
|
|
Returns the hyperbolic sine of the number, defined as (exp(number) - exp(-number))/2 */
|
|
PHP_FUNCTION(sinh)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(sinh(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float cosh(float number)
|
|
Returns the hyperbolic cosine of the number, defined as (exp(number) + exp(-number))/2 */
|
|
PHP_FUNCTION(cosh)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(cosh(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float tanh(float number)
|
|
Returns the hyperbolic tangent of the number, defined as sinh(number)/cosh(number) */
|
|
PHP_FUNCTION(tanh)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(tanh(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float asinh(float number)
|
|
Returns the inverse hyperbolic sine of the number, i.e. the value whose hyperbolic sine is number */
|
|
PHP_FUNCTION(asinh)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(php_asinh(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float acosh(float number)
|
|
Returns the inverse hyperbolic cosine of the number, i.e. the value whose hyperbolic cosine is number */
|
|
PHP_FUNCTION(acosh)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(php_acosh(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float atanh(float number)
|
|
Returns the inverse hyperbolic tangent of the number, i.e. the value whose hyperbolic tangent is number */
|
|
PHP_FUNCTION(atanh)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE(php_atanh(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float pi(void)
|
|
Returns an approximation of pi */
|
|
PHP_FUNCTION(pi)
|
|
{
|
|
RETURN_DOUBLE(M_PI);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool is_finite(float val)
|
|
Returns whether argument is finite */
|
|
PHP_FUNCTION(is_finite)
|
|
{
|
|
double dval;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(dval)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_BOOL(zend_finite(dval));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool is_infinite(float val)
|
|
Returns whether argument is infinite */
|
|
PHP_FUNCTION(is_infinite)
|
|
{
|
|
double dval;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(dval)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_BOOL(zend_isinf(dval));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto bool is_nan(float val)
|
|
Returns whether argument is not a number */
|
|
PHP_FUNCTION(is_nan)
|
|
{
|
|
double dval;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(dval)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_BOOL(zend_isnan(dval));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto number pow(number base, number exponent)
|
|
Returns base raised to the power of exponent. Returns integer result when possible */
|
|
PHP_FUNCTION(pow)
|
|
{
|
|
zval *zbase, *zexp;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
Z_PARAM_ZVAL(zbase)
|
|
Z_PARAM_ZVAL(zexp)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
pow_function(return_value, zbase, zexp);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float exp(float number)
|
|
Returns e raised to the power of the number */
|
|
PHP_FUNCTION(exp)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE(exp(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float expm1(float number)
|
|
Returns exp(number) - 1, computed in a way that accurate even when the value of number is close to zero */
|
|
/*
|
|
WARNING: this function is expermental: it could change its name or
|
|
disappear in the next version of PHP!
|
|
*/
|
|
PHP_FUNCTION(expm1)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE(php_expm1(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float log1p(float number)
|
|
Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero */
|
|
/*
|
|
WARNING: this function is expermental: it could change its name or
|
|
disappear in the next version of PHP!
|
|
*/
|
|
PHP_FUNCTION(log1p)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE(php_log1p(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float log(float number, [float base])
|
|
Returns the natural logarithm of the number, or the base log if base is specified */
|
|
PHP_FUNCTION(log)
|
|
{
|
|
double num, base = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
|
Z_PARAM_DOUBLE(num)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_DOUBLE(base)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (ZEND_NUM_ARGS() == 1) {
|
|
RETURN_DOUBLE(log(num));
|
|
}
|
|
|
|
#ifdef HAVE_LOG2
|
|
if (base == 2.0) {
|
|
RETURN_DOUBLE(log2(num));
|
|
}
|
|
#endif
|
|
|
|
if (base == 10.0) {
|
|
RETURN_DOUBLE(log10(num));
|
|
}
|
|
|
|
if (base == 1.0) {
|
|
RETURN_DOUBLE(ZEND_NAN);
|
|
}
|
|
|
|
if (base <= 0.0) {
|
|
php_error_docref(NULL, E_WARNING, "base must be greater than 0");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
RETURN_DOUBLE(log(num) / log(base));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float log10(float number)
|
|
Returns the base-10 logarithm of the number */
|
|
PHP_FUNCTION(log10)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE(log10(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float sqrt(float number)
|
|
Returns the square root of the number */
|
|
PHP_FUNCTION(sqrt)
|
|
{
|
|
double num;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(num)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE(sqrt(num));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float hypot(float num1, float num2)
|
|
Returns sqrt(num1*num1 + num2*num2) */
|
|
PHP_FUNCTION(hypot)
|
|
{
|
|
double num1, num2;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
Z_PARAM_DOUBLE(num1)
|
|
Z_PARAM_DOUBLE(num2)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
#if HAVE_HYPOT
|
|
RETURN_DOUBLE(hypot(num1, num2));
|
|
#elif defined(_MSC_VER)
|
|
RETURN_DOUBLE(_hypot(num1, num2));
|
|
#else
|
|
RETURN_DOUBLE(sqrt((num1 * num1) + (num2 * num2)));
|
|
#endif
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float deg2rad(float number)
|
|
Converts the number in degrees to the radian equivalent */
|
|
PHP_FUNCTION(deg2rad)
|
|
{
|
|
double deg;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(deg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
RETURN_DOUBLE((deg / 180.0) * M_PI);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float rad2deg(float number)
|
|
Converts the radian number to the equivalent number in degrees */
|
|
PHP_FUNCTION(rad2deg)
|
|
{
|
|
double rad;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_DOUBLE(rad)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE((rad / M_PI) * 180);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_math_basetolong */
|
|
/*
|
|
* Convert a string representation of a base(2-36) number to a long.
|
|
*/
|
|
PHPAPI zend_long _php_math_basetolong(zval *arg, int base)
|
|
{
|
|
zend_long num = 0, digit, onum;
|
|
zend_long i;
|
|
char c, *s;
|
|
|
|
if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
|
|
return 0;
|
|
}
|
|
|
|
s = Z_STRVAL_P(arg);
|
|
|
|
for (i = Z_STRLEN_P(arg); i > 0; i--) {
|
|
c = *s++;
|
|
|
|
digit = (c >= '0' && c <= '9') ? c - '0'
|
|
: (c >= 'A' && c <= 'Z') ? c - 'A' + 10
|
|
: (c >= 'a' && c <= 'z') ? c - 'a' + 10
|
|
: base;
|
|
|
|
if (digit >= base) {
|
|
continue;
|
|
}
|
|
|
|
onum = num;
|
|
num = num * base + digit;
|
|
if (num > onum)
|
|
continue;
|
|
|
|
{
|
|
|
|
php_error_docref(NULL, E_WARNING, "Number '%s' is too big to fit in long", s);
|
|
return ZEND_LONG_MAX;
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_math_basetozval */
|
|
/*
|
|
* Convert a string representation of a base(2-36) number to a zval.
|
|
*/
|
|
PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret)
|
|
{
|
|
zend_long num = 0;
|
|
double fnum = 0;
|
|
zend_long i;
|
|
int mode = 0;
|
|
char c, *s;
|
|
zend_long cutoff;
|
|
int cutlim;
|
|
|
|
if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
|
|
return FAILURE;
|
|
}
|
|
|
|
s = Z_STRVAL_P(arg);
|
|
|
|
cutoff = ZEND_LONG_MAX / base;
|
|
cutlim = ZEND_LONG_MAX % base;
|
|
|
|
for (i = Z_STRLEN_P(arg); i > 0; i--) {
|
|
c = *s++;
|
|
|
|
/* might not work for EBCDIC */
|
|
if (c >= '0' && c <= '9')
|
|
c -= '0';
|
|
else if (c >= 'A' && c <= 'Z')
|
|
c -= 'A' - 10;
|
|
else if (c >= 'a' && c <= 'z')
|
|
c -= 'a' - 10;
|
|
else
|
|
continue;
|
|
|
|
if (c >= base)
|
|
continue;
|
|
|
|
switch (mode) {
|
|
case 0: /* Integer */
|
|
if (num < cutoff || (num == cutoff && c <= cutlim)) {
|
|
num = num * base + c;
|
|
break;
|
|
} else {
|
|
fnum = (double)num;
|
|
mode = 1;
|
|
}
|
|
/* fall-through */
|
|
case 1: /* Float */
|
|
fnum = fnum * base + c;
|
|
}
|
|
}
|
|
|
|
if (mode == 1) {
|
|
ZVAL_DOUBLE(ret, fnum);
|
|
} else {
|
|
ZVAL_LONG(ret, num);
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_math_longtobase */
|
|
/*
|
|
* Convert a long to a string containing a base(2-36) representation of
|
|
* the number.
|
|
*/
|
|
PHPAPI zend_string * _php_math_longtobase(zval *arg, int base)
|
|
{
|
|
static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
char buf[(sizeof(zend_ulong) << 3) + 1];
|
|
char *ptr, *end;
|
|
zend_ulong value;
|
|
|
|
if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) {
|
|
return ZSTR_EMPTY_ALLOC();
|
|
}
|
|
|
|
value = Z_LVAL_P(arg);
|
|
|
|
end = ptr = buf + sizeof(buf) - 1;
|
|
*ptr = '\0';
|
|
|
|
do {
|
|
ZEND_ASSERT(ptr > buf);
|
|
*--ptr = digits[value % base];
|
|
value /= base;
|
|
} while (value);
|
|
|
|
return zend_string_init(ptr, end - ptr, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_math_zvaltobase */
|
|
/*
|
|
* Convert a zval to a string containing a base(2-36) representation of
|
|
* the number.
|
|
*/
|
|
PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base)
|
|
{
|
|
static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
|
|
if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
|
|
return ZSTR_EMPTY_ALLOC();
|
|
}
|
|
|
|
if (Z_TYPE_P(arg) == IS_DOUBLE) {
|
|
double fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
|
|
char *ptr, *end;
|
|
char buf[(sizeof(double) << 3) + 1];
|
|
|
|
/* Don't try to convert +/- infinity */
|
|
if (fvalue == ZEND_INFINITY || fvalue == -ZEND_INFINITY) {
|
|
php_error_docref(NULL, E_WARNING, "Number too large");
|
|
return ZSTR_EMPTY_ALLOC();
|
|
}
|
|
|
|
end = ptr = buf + sizeof(buf) - 1;
|
|
*ptr = '\0';
|
|
|
|
do {
|
|
*--ptr = digits[(int) fmod(fvalue, base)];
|
|
fvalue /= base;
|
|
} while (ptr > buf && fabs(fvalue) >= 1);
|
|
|
|
return zend_string_init(ptr, end - ptr, 0);
|
|
}
|
|
|
|
return _php_math_longtobase(arg, base);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int bindec(string binary_number)
|
|
Returns the decimal equivalent of the binary number */
|
|
PHP_FUNCTION(bindec)
|
|
{
|
|
zval *arg;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(arg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_to_string_ex(arg);
|
|
if (_php_math_basetozval(arg, 2, return_value) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int hexdec(string hexadecimal_number)
|
|
Returns the decimal equivalent of the hexadecimal number */
|
|
PHP_FUNCTION(hexdec)
|
|
{
|
|
zval *arg;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(arg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_to_string_ex(arg);
|
|
if (_php_math_basetozval(arg, 16, return_value) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int octdec(string octal_number)
|
|
Returns the decimal equivalent of an octal string */
|
|
PHP_FUNCTION(octdec)
|
|
{
|
|
zval *arg;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(arg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_to_string_ex(arg);
|
|
if (_php_math_basetozval(arg, 8, return_value) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string decbin(int decimal_number)
|
|
Returns a string containing a binary representation of the number */
|
|
PHP_FUNCTION(decbin)
|
|
{
|
|
zval *arg;
|
|
zend_string *result;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(arg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_to_long_ex(arg);
|
|
result = _php_math_longtobase(arg, 2);
|
|
RETURN_STR(result);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string decoct(int decimal_number)
|
|
Returns a string containing an octal representation of the given number */
|
|
PHP_FUNCTION(decoct)
|
|
{
|
|
zval *arg;
|
|
zend_string *result;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(arg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_to_long_ex(arg);
|
|
result = _php_math_longtobase(arg, 8);
|
|
RETURN_STR(result);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string dechex(int decimal_number)
|
|
Returns a string containing a hexadecimal representation of the given number */
|
|
PHP_FUNCTION(dechex)
|
|
{
|
|
zval *arg;
|
|
zend_string *result;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
Z_PARAM_ZVAL(arg)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
convert_to_long_ex(arg);
|
|
result = _php_math_longtobase(arg, 16);
|
|
RETURN_STR(result);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto string base_convert(string number, int frombase, int tobase)
|
|
Converts a number in a string from any base <= 36 to any base <= 36 */
|
|
PHP_FUNCTION(base_convert)
|
|
{
|
|
zval *number, temp;
|
|
zend_long frombase, tobase;
|
|
zend_string *result;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(3, 3)
|
|
Z_PARAM_ZVAL(number)
|
|
Z_PARAM_LONG(frombase)
|
|
Z_PARAM_LONG(tobase)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
convert_to_string_ex(number);
|
|
|
|
if (frombase < 2 || frombase > 36) {
|
|
php_error_docref(NULL, E_WARNING, "Invalid `from base' (" ZEND_LONG_FMT ")", frombase);
|
|
RETURN_FALSE;
|
|
}
|
|
if (tobase < 2 || tobase > 36) {
|
|
php_error_docref(NULL, E_WARNING, "Invalid `to base' (" ZEND_LONG_FMT ")", tobase);
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
if(_php_math_basetozval(number, (int)frombase, &temp) == FAILURE) {
|
|
RETURN_FALSE;
|
|
}
|
|
result = _php_math_zvaltobase(&temp, (int)tobase);
|
|
RETVAL_STR(result);
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ _php_math_number_format
|
|
*/
|
|
PHPAPI zend_string *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
|
|
{
|
|
return _php_math_number_format_ex(d, dec, &dec_point, 1, &thousand_sep, 1);
|
|
}
|
|
|
|
PHPAPI zend_string *_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)
|
|
{
|
|
zend_string *res;
|
|
zend_string *tmpbuf;
|
|
char *s, *t; /* source, target */
|
|
char *dp;
|
|
size_t integral;
|
|
size_t reslen = 0;
|
|
int count = 0;
|
|
int is_negative=0;
|
|
|
|
if (d < 0) {
|
|
is_negative = 1;
|
|
d = -d;
|
|
}
|
|
|
|
dec = MAX(0, dec);
|
|
d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);
|
|
tmpbuf = strpprintf(0, "%.*F", dec, d);
|
|
if (tmpbuf == NULL) {
|
|
return NULL;
|
|
} else if (!isdigit((int)ZSTR_VAL(tmpbuf)[0])) {
|
|
return tmpbuf;
|
|
}
|
|
|
|
/* Check if the number is no longer negative after rounding */
|
|
if (is_negative && d == 0) {
|
|
is_negative = 0;
|
|
}
|
|
|
|
/* find decimal point, if expected */
|
|
if (dec) {
|
|
dp = strpbrk(ZSTR_VAL(tmpbuf), ".,");
|
|
} else {
|
|
dp = NULL;
|
|
}
|
|
|
|
/* calculate the length of the return buffer */
|
|
if (dp) {
|
|
integral = (dp - ZSTR_VAL(tmpbuf));
|
|
} else {
|
|
/* no decimal point was found */
|
|
integral = ZSTR_LEN(tmpbuf);
|
|
}
|
|
|
|
/* allow for thousand separators */
|
|
if (thousand_sep) {
|
|
integral = zend_safe_addmult((integral-1)/3, thousand_sep_len, integral, "number formatting");
|
|
}
|
|
|
|
reslen = integral;
|
|
|
|
if (dec) {
|
|
reslen += dec;
|
|
|
|
if (dec_point) {
|
|
reslen = zend_safe_addmult(reslen, 1, dec_point_len, "number formatting");
|
|
}
|
|
}
|
|
|
|
/* add a byte for minus sign */
|
|
if (is_negative) {
|
|
reslen++;
|
|
}
|
|
res = zend_string_alloc(reslen, 0);
|
|
|
|
s = ZSTR_VAL(tmpbuf) + ZSTR_LEN(tmpbuf) - 1;
|
|
t = ZSTR_VAL(res) + reslen;
|
|
*t-- = '\0';
|
|
|
|
/* copy the decimal places.
|
|
* Take care, as the sprintf implementation may return less places than
|
|
* we requested due to internal buffer limitations */
|
|
if (dec) {
|
|
size_t declen = (dp ? s - dp : 0);
|
|
size_t topad = (size_t)dec > declen ? dec - declen : 0;
|
|
|
|
/* pad with '0's */
|
|
while (topad--) {
|
|
*t-- = '0';
|
|
}
|
|
|
|
if (dp) {
|
|
s -= declen + 1; /* +1 to skip the point */
|
|
t -= declen;
|
|
|
|
/* now copy the chars after the point */
|
|
memcpy(t + 1, dp + 1, declen);
|
|
}
|
|
|
|
/* add decimal point */
|
|
if (dec_point) {
|
|
t -= dec_point_len;
|
|
memcpy(t + 1, dec_point, dec_point_len);
|
|
}
|
|
}
|
|
|
|
/* copy the numbers before the decimal point, adding thousand
|
|
* separator every three digits */
|
|
while (s >= ZSTR_VAL(tmpbuf)) {
|
|
*t-- = *s--;
|
|
if (thousand_sep && (++count%3)==0 && s >= ZSTR_VAL(tmpbuf)) {
|
|
t -= thousand_sep_len;
|
|
memcpy(t + 1, thousand_sep, thousand_sep_len);
|
|
}
|
|
}
|
|
|
|
/* and a minus sign, if needed */
|
|
if (is_negative) {
|
|
*t-- = '-';
|
|
}
|
|
|
|
ZSTR_LEN(res) = reslen;
|
|
zend_string_release_ex(tmpbuf, 0);
|
|
return res;
|
|
}
|
|
|
|
/* {{{ proto string number_format(float number [, int num_decimal_places [, string dec_separator, string thousands_separator]])
|
|
Formats a number with grouped thousands */
|
|
PHP_FUNCTION(number_format)
|
|
{
|
|
double num;
|
|
zend_long dec = 0;
|
|
char *thousand_sep = NULL, *dec_point = NULL;
|
|
char thousand_sep_chr = ',', dec_point_chr = '.';
|
|
size_t thousand_sep_len = 0, dec_point_len = 0;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(1, 4)
|
|
Z_PARAM_DOUBLE(num)
|
|
Z_PARAM_OPTIONAL
|
|
Z_PARAM_LONG(dec)
|
|
Z_PARAM_STRING_EX(dec_point, dec_point_len, 1, 0)
|
|
Z_PARAM_STRING_EX(thousand_sep, thousand_sep_len, 1, 0)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
switch(ZEND_NUM_ARGS()) {
|
|
case 1:
|
|
RETURN_STR(_php_math_number_format(num, 0, dec_point_chr, thousand_sep_chr));
|
|
break;
|
|
case 2:
|
|
RETURN_STR(_php_math_number_format(num, (int)dec, dec_point_chr, thousand_sep_chr));
|
|
break;
|
|
case 4:
|
|
if (dec_point == NULL) {
|
|
dec_point = &dec_point_chr;
|
|
dec_point_len = 1;
|
|
}
|
|
|
|
if (thousand_sep == NULL) {
|
|
thousand_sep = &thousand_sep_chr;
|
|
thousand_sep_len = 1;
|
|
}
|
|
|
|
RETVAL_STR(_php_math_number_format_ex(num, (int)dec,
|
|
dec_point, dec_point_len, thousand_sep, thousand_sep_len));
|
|
break;
|
|
default:
|
|
WRONG_PARAM_COUNT;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto float fmod(float x, float y)
|
|
Returns the remainder of dividing x by y as a float */
|
|
PHP_FUNCTION(fmod)
|
|
{
|
|
double num1, num2;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
Z_PARAM_DOUBLE(num1)
|
|
Z_PARAM_DOUBLE(num2)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
RETURN_DOUBLE(fmod(num1, num2));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ proto int intdiv(int dividend, int divisor)
|
|
Returns the integer quotient of the division of dividend by divisor */
|
|
PHP_FUNCTION(intdiv)
|
|
{
|
|
zend_long dividend, divisor;
|
|
|
|
ZEND_PARSE_PARAMETERS_START(2, 2)
|
|
Z_PARAM_LONG(dividend)
|
|
Z_PARAM_LONG(divisor)
|
|
ZEND_PARSE_PARAMETERS_END();
|
|
|
|
if (divisor == 0) {
|
|
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
|
|
return;
|
|
} else if (divisor == -1 && dividend == ZEND_LONG_MIN) {
|
|
/* Prevent overflow error/crash ... really should not happen:
|
|
We don't return a float here as that violates function contract */
|
|
zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Division of PHP_INT_MIN by -1 is not an integer");
|
|
return;
|
|
}
|
|
|
|
RETURN_LONG(dividend / divisor);
|
|
}
|
|
/* }}} */
|