From e6281ab38bb6cd87cef572a12811b68f1f6785cc Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 10 Mar 2004 15:57:49 +0000 Subject: [PATCH] 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. --- ext/standard/math.c | 41 +++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 6d58ba54df..262ec23e1d 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -23,6 +23,7 @@ #include "php.h" #include "php_math.h" +#include "zend_multiply.h" #include #include @@ -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)) ); } /* }}} */ -- 2.40.0