|
|
|
@ -23,6 +23,7 @@ |
|
|
|
|
|
|
|
#include "php.h" |
|
|
|
#include "php_math.h" |
|
|
|
#include "zend_multiply.h" |
|
|
|
|
|
|
|
#include <math.h> |
|
|
|
#include <float.h> |
|
|
|
@ -449,22 +450,38 @@ PHP_FUNCTION(pow) |
|
|
|
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); |
|
|
|
|
|
|
|
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 (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); |
|
|
|
|
|
|
|
/* go ahead and calculate things. */ |
|
|
|
dval = pow(Z_DVAL_P(zbase),Z_DVAL_P(zexp)); |
|
|
|
|
|
|
|
/* 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); |
|
|
|
} |
|
|
|
|
|
|
|
/* otherwise just return the double. */ |
|
|
|
RETURN_DOUBLE(dval); |
|
|
|
RETURN_DOUBLE( pow(Z_DVAL_P(zbase),Z_DVAL_P(zexp)) ); |
|
|
|
} |
|
|
|
/* }}} */ |
|
|
|
|
|
|
|
|