#include "php.h"
#include "php_math.h"
+#include "zend_multiply.h"
#include <math.h>
#include <float.h>
/* {{{ proto int abs(int number)
Return the absolute value of the number */
-PHP_FUNCTION(abs)
+PHP_FUNCTION(abs)
{
zval **value;
-
+
if (ZEND_NUM_ARGS()!=1||zend_get_parameters_ex(1, &value)==FAILURE) {
WRONG_PARAM_COUNT;
}
convert_scalar_to_number_ex(value);
-
+
if (Z_TYPE_PP(value) == IS_DOUBLE) {
RETURN_DOUBLE(fabs(Z_DVAL_PP(value)));
} else if (Z_TYPE_PP(value) == IS_LONG) {
RETURN_FALSE;
}
-/* }}} */
+/* }}} */
/* {{{ proto float ceil(float number)
Returns the next highest integer value of the number */
-PHP_FUNCTION(ceil)
+PHP_FUNCTION(ceil)
{
zval **value;
-
+
if (ZEND_NUM_ARGS()!=1||zend_get_parameters_ex(1, &value)==FAILURE) {
WRONG_PARAM_COUNT;
}
PHP_FUNCTION(floor)
{
zval **value;
-
+
if (ZEND_NUM_ARGS()!=1||zend_get_parameters_ex(1, &value)==FAILURE) {
WRONG_PARAM_COUNT;
}
zval **value, **precision;
int places = 0;
double return_val;
-
+
if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
zend_get_parameters_ex(ZEND_NUM_ARGS(), &value, &precision) == FAILURE) {
WRONG_PARAM_COUNT;
PHP_FUNCTION(pow)
{
zval *zbase, *zexp;
- double dval;
- zend_bool wantlong;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/", &zbase, &zexp) == FAILURE) {
return;
convert_scalar_to_number(zexp TSRMLS_CC);
/* if both base and exponent were longs, we'll try to get a long out */
- wantlong = Z_TYPE_P(zbase) == IS_LONG
- && Z_TYPE_P(zexp ) == IS_LONG && Z_LVAL_P(zexp) >= 0;
+ if (Z_TYPE_P(zbase) == IS_LONG && Z_TYPE_P(zexp) == IS_LONG && Z_LVAL_P(zexp) >= 0) {
+ long l1 = 1, l2 = Z_LVAL_P(zbase), i = Z_LVAL_P(zexp);
- convert_to_double(zbase);
- convert_to_double(zexp);
-
- /* go ahead and calculate things. */
- dval = pow(Z_DVAL_P(zbase),Z_DVAL_P(zexp));
+ if (i == 0) {
+ RETURN_LONG(1L);
+ } else if (l2 == 0) {
+ RETURN_LONG(0);
+ }
+
+ /* calculate pow(long,long) in O(log exp) operations, bail if overflow */
+ while (i >= 1) {
+ int overflow;
+ double dval;
- /* if we wanted a long, and dval < LONG_MAX, it must be a long. */
- if (wantlong && zend_finite(dval) && dval <= (double)LONG_MAX) {
- RETURN_LONG((long)dval);
+ if (i % 2) {
+ --i;
+ ZEND_SIGNED_MULTIPLY_LONG(l1,l2,l1,dval,overflow);
+ if (overflow) RETURN_DOUBLE(dval * pow(l2,i));
+ } else {
+ i /= 2;
+ ZEND_SIGNED_MULTIPLY_LONG(l2,l2,l2,dval,overflow);
+ if (overflow) RETURN_DOUBLE((double)l1 * pow(dval,i));
+ }
+ if (i == 0) {
+ RETURN_LONG(l1);
+ }
+ }
}
+ convert_to_double(zbase);
+ convert_to_double(zexp);
- /* otherwise just return the double. */
- RETURN_DOUBLE(dval);
+ RETURN_DOUBLE( pow(Z_DVAL_P(zbase),Z_DVAL_P(zexp)) );
}
/* }}} */
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
+ WARNING: this function is expermental: it could change its name or
disappear in the next version of PHP!
*/
/* }}} */
/* {{{ 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 */
+ 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
+ WARNING: this function is expermental: it could change its name or
disappear in the next version of PHP!
*/
PHP_FUNCTION(log)
{
zval **num, **base;
-
+
switch (ZEND_NUM_ARGS()) {
case 1:
if (zend_get_parameters_ex(1, &num) == FAILURE) {
}
convert_to_double_ex(num);
convert_to_double_ex(base);
-
+
if (Z_DVAL_PP(base) <= 0.0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0");
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0");
RETURN_FALSE;
}
RETURN_DOUBLE(log(Z_DVAL_PP(num)) / log(Z_DVAL_PP(base)));
/* {{{ proto float hypot(float num1, float num2)
- Returns sqrt(num1*num1 + num2*num2) */
+ Returns sqrt(num1*num1 + num2*num2) */
/*
- WARNING: this function is expermental: it could change its name or
+ WARNING: this function is expermental: it could change its name or
disappear in the next version of PHP!
*/
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;
}
cutoff = LONG_MAX / base;
cutlim = LONG_MAX % base;
-
+
for (i = Z_STRLEN_P(arg); i > 0; i--) {
c = *s++;
/* might not work for EBCDIC */
- if (c >= '0' && c <= '9')
+ if (c >= '0' && c <= '9')
c -= '0';
- else if (c >= 'A' && c <= 'Z')
+ else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
- else if (c >= 'a' && c <= 'z')
+ 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)) {
/* fall-through */
case 1: /* Float */
fnum = fnum * base + c;
- }
+ }
}
if (mode == 1) {
return estrndup(ptr, end - ptr);
}
-
+
return _php_math_longtobase(arg, base);
-}
+}
/* }}} */
/* {{{ proto int bindec(string binary_number)
PHP_FUNCTION(bindec)
{
zval **arg;
-
+
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
PHP_FUNCTION(hexdec)
{
zval **arg;
-
+
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
PHP_FUNCTION(octdec)
{
zval **arg;
-
+
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
}
result = _php_math_zvaltobase(&temp, Z_LVAL_PP(tobase) TSRMLS_CC);
RETVAL_STRING(result, 0);
-}
+}
/* }}} */
/* {{{ _php_math_number_format */
if (thousand_sep) {
integral += (integral-1) / 3;
}
-
+
reslen = integral;
-
+
if (dec) {
reslen += 1 + dec;
}
while (topad--) {
*t-- = '0';
}
-
+
if (dp) {
/* now copy the chars after the point */
memcpy(t - declen + 1, dp + 1, declen);
}
efree(tmpbuf);
-
+
return resbuf;
}
{
zval **num, **dec, **t_s, **d_p;
char thousand_sep=',', dec_point='.';
-
+
switch(ZEND_NUM_ARGS()) {
case 1:
if (zend_get_parameters_ex(1, &num)==FAILURE) {
if (Z_STRLEN_PP(t_s)==1) {
thousand_sep=Z_STRVAL_PP(t_s)[0];
} else if(Z_STRLEN_PP(t_s)==0) {
- thousand_sep=0;
+ thousand_sep=0;
}
RETURN_STRING(_php_math_number_format(Z_DVAL_PP(num), Z_LVAL_PP(dec), dec_point, thousand_sep), 0);
break;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
return;
}
-
+
Z_DVAL_P(return_value) = fmod(num1, num2);
Z_TYPE_P(return_value) = IS_DOUBLE;
}