Browse Source

Don't use fp arithmetic for int results

# FP arithmetic is not accurate enough on 64-bit archs
# This patch relies on ZEND_SIGNED_MULTIPLY_LONG(),
# so that should be fixed as well.
PEAR_1_4DEV
Ard Biesheuvel 22 years ago
parent
commit
e6281ab38b
  1. 41
      ext/standard/math.c

41
ext/standard/math.c

@ -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)) );
}
/* }}} */

Loading…
Cancel
Save