Hi, I've tested the pow() function thoroughly on my system (linux debian). I'm confident it's okay now. Could someone commit this? Or even better, can I have Karma for php4/ext[/standard]? Tests are included, would someone with 64bit int's please run them? They should work. If they succeed, please drop me a line (and of course also when they don't) Greetz, Jeroen Jeroen van Wolffelaar [EMAIL PROTECTED] http://www.A-Eskwadraat.nl/~jeroen
Index: math.c =================================================================== RCS file: /repository/php4/ext/standard/math.c,v retrieving revision 1.41 diff -u -r1.41 math.c --- math.c 2001/06/06 13:05:51 1.41 +++ math.c 2001/07/08 18:04:36 @@ -275,22 +275,113 @@ } /* }}} */ -/* {{{ proto double pow(double base, double exponent) - Returns base raised to the power of exponent */ + +/* {{{ proto number pow(number lbase, number lexponent) + Returns lbase raised to the power of lexponent. Returns + integer result when possible. */ + PHP_FUNCTION(pow) { - zval **num1, **num2; + /* FIXME: What is our policy on float-overflow? With pow, it's + * extremely easy to request results that won't fit in any double. + */ + + zval **zbase, **zexp; + long lbase,lexp; - if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2,&num1,&num2) == FAILURE) { + if (ZEND_NUM_ARGS() != 2) { WRONG_PARAM_COUNT; + } + zend_get_parameters_ex(ZEND_NUM_ARGS(),&zbase,&zexp); + convert_scalar_to_number_ex(zbase); + convert_scalar_to_number_ex(zexp); + if (Z_TYPE_PP(zbase) != IS_LONG && Z_TYPE_PP(zbase) != IS_DOUBLE || + Z_TYPE_PP(zexp ) != IS_LONG && Z_TYPE_PP(zexp ) != IS_DOUBLE) { + php_error(E_WARNING,"Invalid argument(s) passed to pow()"); + RETURN_FALSE; + } + + if (Z_TYPE_PP(zexp) == IS_DOUBLE) { + /* pow(?,double), this is the ^^ case */ + double dbase; + dbase = Z_TYPE_PP(zbase) == IS_LONG ? (double) Z_LVAL_PP(zbase) + + : Z_DVAL_PP(zbase); + if ( dbase <= 0.0 ) { + /* Note that with the old behaviour, php pow() returned bogus + results. Try pow(-1,2.5) in PHP <= 4.0.6 ... */ + php_error(E_WARNING,"Trying to raise a nonpositive value to a +broken power"); + RETURN_FALSE; + } + RETURN_DOUBLE(exp(log(dbase) * Z_DVAL_PP(zexp))); } - convert_to_double_ex(num1); - convert_to_double_ex(num2); - RETURN_DOUBLE(pow((*num1)->value.dval, (*num2)->value.dval)); + + /* pow(?,int), this is the ** case */ + + lexp = Z_LVAL_PP(zexp); + + + if (Z_TYPE_PP(zbase) == IS_DOUBLE) { + /* pow(double,int) */ + if (lexp == 0) { + RETURN_DOUBLE(1.0); + } + if (Z_DVAL_PP(zbase) > 0.0) { + RETURN_DOUBLE(exp(log(Z_DVAL_PP(zbase)) * lexp)); + } else if (Z_DVAL_PP(zbase) == 0.0) { + if (lexp < 0) { + php_error(E_WARNING,"Division by zero (pow(0.0,-n))"); + RETURN_FALSE; + } else { + RETURN_DOUBLE(0.0); + } + } else { /* lbase < 0.0 */ + double pos_result = exp(log(-Z_DVAL_PP(zbase)) * +(double)lexp); + RETURN_DOUBLE(lexp & 1 ? -pos_result : pos_result); + } + + } + + /* pow(int,int) */ + if (lexp == 0) { + RETURN_LONG(1); + } + + lbase = Z_LVAL_PP(zbase); + + if (lbase == -1) { + RETURN_LONG( lexp & 1 ? -1 : 1 ); /* if lexp=odd ... */ + } else if (lbase == 0) { + if (lexp < 0) { + php_error(E_WARNING,"Division by zero (pow(0,-n))"); + RETURN_FALSE; + } else { + RETURN_LONG(0); + } + } else if (lbase == 1) { + RETURN_LONG(1); + } else { + /* abs(lbase) > 1 */ + double dval = exp(log((double) (lbase>0?lbase:-lbase)) * (double) +lexp); + long result = 1; + if (lexp < 0 || dval > (double) LONG_MAX) { + /* 1/n ( abs(n) > 1 ) || overflow */ + RETURN_DOUBLE((lexp & 1) && lbase < 0 ? -dval : dval); + } + + /* Fasted algorithm there is, runs in O(logn), where n=lexp */ + while (lexp > 0) { + if (lexp & 1) /* odd */ + result *= lbase; + lexp >>= 1; + lbase *= lbase; + } + RETURN_LONG(result); + } } /* }}} */ + /* {{{ proto double exp(double number) Returns e raised to the power of the number */ Index: tests/math/001.phpt =================================================================== RCS file: /repository/php4/ext/standard/tests/math/001.phpt,v retrieving revision 1.1 diff -u -r1.1 001.phpt --- tests/math/001.phpt 2000/08/27 19:45:59 1.1 +++ tests/math/001.phpt 2001/07/08 18:04:37 @@ -3,11 +3,14 @@ --POST-- --GET-- --FILE-- -<?php +<?php echo abs(-1) . "\n"; echo abs(-1.5) . "\n"; echo abs("-1") . "\n"; echo abs("-1.5") . "\n"; + echo abs(-2147483647) . "\n"; + echo abs(-2147483648) . "\n"; + echo abs(-2147483649) . "\n"; echo ceil(-1.5) . "\n"; echo ceil(1.5) . "\n"; echo floor(-1.5) . "\n"; @@ -19,6 +22,9 @@ 1.5 1 1.5 +2147483647 +2147483648 +2147483649 -1 2 -2
-- PHP Development Mailing List <http://www.php.net/> To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] To contact the list administrators, e-mail: [EMAIL PROTECTED]