#include "php.h"
#include "php_math.h"
#include "zend_multiply.h"
#include "zend_exceptions.h"
#include <math.h>
#include <float.h>
#include <stdlib.h>
#include "basic_functions.h"
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};
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;
}
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};
if (power < 0 || power > 22) {
return pow(10.0, (double)power);
}
return powers[power];
}
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;
}
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 (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;
}
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;
f2 = php_intpow10(abs((int)use_precision));
tmp_value = tmp_value / f2;
} else {
if (places >= 0) {
tmp_value = value * f1;
} else {
tmp_value = value / f1;
}
if (fabs(tmp_value) >= 1e15) {
return value;
}
}
tmp_value = php_round_helper(tmp_value, mode);
if (abs(places) < 23) {
if (places > 0) {
tmp_value = tmp_value / f1;
} else {
tmp_value = tmp_value * f1;
}
} else {
char buf[40];
snprintf(buf, 39, "%15fe%d", tmp_value, -places);
buf[39] = '\0';
tmp_value = zend_strtod(buf, NULL);
if (!zend_finite(tmp_value) || zend_isnan(tmp_value)) {
tmp_value = value;
}
}
return tmp_value;
}
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
}
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 (DBL_MAX+DBL_MAX)-(DBL_MAX+DBL_MAX);
}
# else
return(log(x + sqrt(x * x - 1)));
# endif
#endif
}
static double php_atanh(double z)
{
#ifdef HAVE_ATANH
return(atanh(z));
#else
return(0.5 * log((1 + z) / (1 - z)));
#endif
}
static double php_log1p(double x)
{
#ifdef HAVE_LOG1P
return(log1p(x));
#else
return(log(1 + x));
#endif
}
static double php_expm1(double x)
{
#if !defined(PHP_WIN32) && !defined(NETWARE)
return(expm1(x));
#else
return(exp(x) - 1);
#endif
}
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;
}
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;
}
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;
}
PHP_FUNCTION(round)
{
zval *value;
int places = 0;
zend_long precision = 0;
zend_long mode = PHP_ROUND_HALF_UP;
double return_val;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|ll", &value, &precision, &mode) == FAILURE) {
return;
}
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:
if (places >= 0) {
RETURN_DOUBLE((double) Z_LVAL_P(value));
}
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;
}
}
PHP_FUNCTION(sin)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(sin(num));
}
PHP_FUNCTION(cos)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(cos(num));
}
PHP_FUNCTION(tan)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(tan(num));
}
PHP_FUNCTION(asin)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(asin(num));
}
PHP_FUNCTION(acos)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(acos(num));
}
PHP_FUNCTION(atan)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(atan(num));
}
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));
}
PHP_FUNCTION(sinh)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(sinh(num));
}
PHP_FUNCTION(cosh)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(cosh(num));
}
PHP_FUNCTION(tanh)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(tanh(num));
}
PHP_FUNCTION(asinh)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(php_asinh(num));
}
PHP_FUNCTION(acosh)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(php_acosh(num));
}
PHP_FUNCTION(atanh)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(php_atanh(num));
}
PHP_FUNCTION(pi)
{
RETURN_DOUBLE(M_PI);
}
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));
}
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));
}
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));
}
PHP_FUNCTION(pow)
{
zval *zbase, *zexp;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z/z/", &zbase, &zexp) == FAILURE) {
return;
}
pow_function(return_value, zbase, zexp);
}
PHP_FUNCTION(exp)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(exp(num));
}
PHP_FUNCTION(expm1)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(php_expm1(num));
}
PHP_FUNCTION(log1p)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(php_log1p(num));
}
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(php_get_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));
}
PHP_FUNCTION(log10)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(log10(num));
}
PHP_FUNCTION(sqrt)
{
double num;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_DOUBLE(num)
ZEND_PARSE_PARAMETERS_END();
RETURN_DOUBLE(sqrt(num));
}
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
}
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);
}
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);
}
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;
}
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++;
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:
if (num < cutoff || (num == cutoff && c <= cutlim)) {
num = num * base + c;
break;
} else {
fnum = (double)num;
mode = 1;
}
case 1:
fnum = fnum * base + c;
}
}
if (mode == 1) {
ZVAL_DOUBLE(ret, fnum);
} else {
ZVAL_LONG(ret, num);
}
return SUCCESS;
}
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 {
*--ptr = digits[value % base];
value /= base;
} while (ptr > buf && value);
return zend_string_init(ptr, end - ptr, 0);
}
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));
char *ptr, *end;
char buf[(sizeof(double) << 3) + 1];
if (fvalue == HUGE_VAL || fvalue == -HUGE_VAL) {
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);
}
PHP_FUNCTION(bindec)
{
zval *arg;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
convert_to_string_ex(arg);
if (_php_math_basetozval(arg, 2, return_value) == FAILURE) {
RETURN_FALSE;
}
}
PHP_FUNCTION(hexdec)
{
zval *arg;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
convert_to_string_ex(arg);
if (_php_math_basetozval(arg, 16, return_value) == FAILURE) {
RETURN_FALSE;
}
}
PHP_FUNCTION(octdec)
{
zval *arg;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
convert_to_string_ex(arg);
if (_php_math_basetozval(arg, 8, return_value) == FAILURE) {
RETURN_FALSE;
}
}
PHP_FUNCTION(decbin)
{
zval *arg;
zend_string *result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
convert_to_long_ex(arg);
result = _php_math_longtobase(arg, 2);
RETURN_STR(result);
}
PHP_FUNCTION(decoct)
{
zval *arg;
zend_string *result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
convert_to_long_ex(arg);
result = _php_math_longtobase(arg, 8);
RETURN_STR(result);
}
PHP_FUNCTION(dechex)
{
zval *arg;
zend_string *result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &arg) == FAILURE) {
return;
}
convert_to_long_ex(arg);
result = _php_math_longtobase(arg, 16);
RETURN_STR(result);
}
PHP_FUNCTION(base_convert)
{
zval *number, temp;
zend_long frombase, tobase;
zend_string *result;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zll", &number, &frombase, &tobase) == FAILURE) {
return;
}
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);
}
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;
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;
}
if (dec) {
dp = strpbrk(ZSTR_VAL(tmpbuf), ".,");
} else {
dp = NULL;
}
if (dp) {
integral = (dp - ZSTR_VAL(tmpbuf));
} else {
integral = ZSTR_LEN(tmpbuf);
}
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");
}
}
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';
if (dec) {
size_t declen = (dp ? s - dp : 0);
size_t topad = dec > declen ? dec - declen : 0;
while (topad--) {
*t-- = '0';
}
if (dp) {
s -= declen + 1;
t -= declen;
memcpy(t + 1, dp + 1, declen);
}
if (dec_point) {
t -= dec_point_len;
memcpy(t + 1, dec_point, dec_point_len);
}
}
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);
}
}
if (is_negative) {
*t-- = '-';
}
ZSTR_LEN(res) = reslen;
zend_string_release(tmpbuf);
return res;
}
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;
}
}
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));
}
PHP_FUNCTION(intdiv)
{
zend_long dividend, divisor;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", ÷nd, &divisor) == FAILURE) {
return;
}
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) {
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);
}