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]