]> granicus.if.org Git - php/commitdiff
Fixed pow(), and added finite(), isinf(), and isnan(). Also fixed
authorjim winstead <jimw@php.net>
Sat, 5 Jan 2002 03:45:11 +0000 (03:45 +0000)
committerjim winstead <jimw@php.net>
Sat, 5 Jan 2002 03:45:11 +0000 (03:45 +0000)
pow() tests.
@- Fixed pow(), and added finite(), isinf(), and isnan(). (Jim)
# Jeroen was on crack, and apparently flunked arithmetic. Names of new
# functions subject to change if people get persnickety about them.
# (They're currently the same as the underlying C library function
# names. Hope nobody forgets to update the tests if they change the
# names.)
# Oh, and pow() uses the new parameter-passing API now.

ext/standard/basic_functions.c
ext/standard/math.c
ext/standard/php_math.h
ext/standard/tests/math/pow.phpt

index f5cec794ca040f8be80c80bd94fe20e0eb51c5dd..2b5eeb4398cdd54866caec8ab808f3ca9adc28ab 100644 (file)
@@ -462,6 +462,9 @@ function_entry basic_functions[] = {
 #endif
 
        PHP_FE(pi,                                                                                                                              NULL)
+       PHP_FE(finite,                                                                                                                  NULL)
+       PHP_FE(isnan,                                                                                                                   NULL)
+       PHP_FE(isinf,                                                                                                                   NULL)
        PHP_FE(pow,                                                                                                                             NULL)
        PHP_FE(exp,                                                                                                                             NULL)
        PHP_FE(log,                                                                                                                             NULL)
index 9b9fdc838cab7e00c8646b58b236f6dc6053b7d4..8e37a81dbd33db96e8271edd3fc650baafa0b154 100644 (file)
@@ -382,117 +382,86 @@ PHP_FUNCTION(pi)
 
 /* }}} */
 
-/* {{{ proto number pow(number base, number exponent)
-   Returns base raised to the power of exponent. Returns
-   integer result when possible. */
 
-PHP_FUNCTION(pow)
+/* {{{ proto bool finite(double val)
+   Returns whether double is finite. */
+PHP_FUNCTION(finite)
 {
-       /* 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;
        double dval;
-       
-       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 (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
+               return;
        }
-       
-       if (Z_TYPE_PP(zexp) == IS_DOUBLE) {
-               /* pow(?, float), this is the ^^ case */
-               convert_to_double_ex(zbase);
-
-               if (Z_DVAL_PP(zbase) < 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(Z_DVAL_PP(zbase)) * Z_DVAL_PP(zexp)));
+       RETURN_BOOL(finite(dval));
+}
+/* }}} */
+
+/* {{{ proto bool isinf(double val)
+   Returns whether double is infinite. */
+PHP_FUNCTION(isinf)
+{
+       double dval;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
+               return;
        }
+       RETURN_BOOL(isinf(dval));
+}
+/* }}} */
 
-       /* pow(?, int), this is the ** case */
+/* {{{ proto bool isnan(double val)
+   Returns whether double is not a number. */
+PHP_FUNCTION(isnan)
+{
+       double dval;
 
-       lexp = Z_LVAL_PP(zexp);
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
+               return;
+       }
+       RETURN_BOOL(isnan(dval));
+}
+/* }}} */
 
+/* {{{ proto number pow(number base, number exponent)
+   Returns base raised to the power of exponent. Returns
+   integer result when possible. */
+PHP_FUNCTION(pow)
+{
+       zval *zbase, *zexp;
+       double dval;
+       zend_bool wantlong;
 
-       if (Z_TYPE_PP(zbase) == IS_DOUBLE) {
-               /* pow(float, 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, [negative integer])");
-                               RETURN_FALSE;
-                       } else {
-                               RETURN_DOUBLE(0.0);
-                       }
-               } else { /* lbase < 0.0 */
-                       dval = exp(log(-Z_DVAL_PP(zbase)) * (double)lexp);
-                       RETURN_DOUBLE(lexp & 1 ? -dval : dval);
-               }
-                       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zbase, &zexp) == FAILURE) {
+               return;
        }
-       
-       /* pow(int, int) */
-       if (lexp == 0) {
-               RETURN_LONG(1);
-       }
-
-       lbase = Z_LVAL_PP(zbase);
-
-       /* lexp != 0 */
-       switch (lbase) {
-               case -1:
-                       RETURN_LONG( lexp & 1 ? -1 : 1 ); /* if lexp=odd ... */
-               case 0:
-                       if (lexp < 0) {
-                               php_error(E_WARNING,
-                                       "Division by zero: pow(0, [negative integer])");
-                               RETURN_FALSE;
-                       } else {
-                               RETURN_LONG(0);
-                       }
-               case 1:
-                       RETURN_LONG(1);
-               default:
-                       /* abs(lbase) > 1 */
-                       dval = exp(log(lbase>0? (double)lbase : -(double)lbase ) * 
-                                                                 (double) lexp);
-                       if (lexp < 0 || dval > (double) LONG_MAX) {
-                               /* 1/n ( abs(n) > 1 ) || overflow */
-                               RETURN_DOUBLE(((lexp & 1) && lbase<0) ? -dval : dval);
-                       }
 
-                       Z_TYPE_P(return_value) = IS_LONG;
-                       Z_LVAL_P(return_value) = 1;
+       if ((Z_TYPE_P(zbase) != IS_LONG && Z_TYPE_P(zbase) != IS_DOUBLE) ||
+               (Z_TYPE_P(zexp ) != IS_LONG && Z_TYPE_P(zexp ) != IS_DOUBLE)) {
+               php_error(E_WARNING, "Invalid argument(s) passed to %s()", get_active_function_name(TSRMLS_C));
+               RETURN_FALSE;
+       }
 
-                       /* loop runs at most log(log(LONG_MAX)) times, i.e. ~ 5 */
-                       while (lexp > 0) { 
-                               if (lexp & 1) /* odd */
-                                       Z_LVAL_P(return_value) *= lbase;
-                               lexp >>= 1;
-                               lbase *= lbase;
-                       }
-                       /* return */
+       /* if both base and exponent were longs, try to get a long out */
+       wantlong = Z_TYPE_P(zbase) == IS_LONG 
+               && Z_TYPE_P(zexp ) == IS_LONG && Z_LVAL_P(zexp) >= 0;
+
+       /* need to SEPERATE_ZVAL? */
+       multi_convert_to_double_ex(2,&zbase,&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 && finite(dval) && dval <= (double)LONG_MAX) {
+               RETURN_LONG((long)dval);
        }
-}
 
+       /* otherwise just return the double. */
+       RETURN_DOUBLE(dval);
+}
 /* }}} */
+
 /* {{{ proto float exp(float number)
    Returns e raised to the power of the number */
 
index fe5c873542677a6c26fa3cb779aef007f8a7da98..71d9b6d88ee94ef26ad222a74c6e9c9d2e0a28c6 100644 (file)
@@ -35,6 +35,9 @@ PHP_FUNCTION(pi);
 PHP_FUNCTION(exp);
 PHP_FUNCTION(log);
 PHP_FUNCTION(log10);
+PHP_FUNCTION(finite);
+PHP_FUNCTION(isinf);
+PHP_FUNCTION(isnan);
 PHP_FUNCTION(pow);
 PHP_FUNCTION(sqrt);
 PHP_FUNCTION(srand);
index cbe5efea99862258aa6250c45b504f741a4feeb5..3480e076cd43d71c94f1c5abb815a3f0d0dc8df3 100644 (file)
@@ -16,18 +16,18 @@ $tests = <<<TESTS
  1    === pow(-2, 0)
 -2    === pow(-2, 1)
  4    === pow(-2, 2)
- 1    === pow(-1,-2)
--1    === pow(-1,-1)
+ 1.0  === pow(-1,-2)
+-1.0  === pow(-1,-1)
  1    === pow(-1, 0)
 -1    === pow(-1, 1)
  1    === pow(-1, 2)
-FALSE ===@pow( 0,-2)
-FALSE ===@pow( 0,-1)
+ TRUE === isinf(pow(0,-2))
+ TRUE === isinf(pow(0,-1))
  1    === pow( 0, 0)
  0    === pow( 0, 1)
  0    === pow( 0, 2)
- 1    === pow( 1,-2)
- 1    === pow( 1,-1)
+ 1.0  === pow( 1,-2)
+ 1.0  === pow( 1,-1)
  1    === pow( 1, 0)
  1    === pow( 1, 1)
  1    === pow( 1, 2)
@@ -36,18 +36,18 @@ FALSE ===@pow( 0,-1)
  1    === pow( 2, 0)
  2    === pow( 2, 1)
  4    === pow( 2, 2)
-FALSE ===@pow(-2,-2.0)
-FALSE ===@pow(-2,-1.0)
-FALSE ===@pow(-2, 0.0)
-FALSE ===@pow(-2, 1.0)
-FALSE ===@pow(-2, 2.0)
-FALSE ===@pow(-1,-2.0)
-FALSE ===@pow(-1,-1.0)
-FALSE ===@pow(-1, 0.0)
-FALSE ===@pow(-1, 1.0)
-FALSE ===@pow(-1, 2.0)
-FALSE ===@pow( 0,-2.0)
-FALSE ===@pow( 0,-1.0)
+ 0.25 === pow(-2,-2.0)
+-0.5  === pow(-2,-1.0)
+ 1.0  === pow(-2, 0.0)
+-2.0  === pow(-2, 1.0)
+ 4.0  === pow(-2, 2.0)
+ 1.0  === pow(-1,-2.0)
+-1.0  === pow(-1,-1.0)
+ 1.0  === pow(-1, 0.0)
+-1.0  === pow(-1, 1.0)
+ 1.0  === pow(-1, 2.0)
+ TRUE === isinf(pow(0,-2.0))
+ TRUE === isinf(pow(0,-1.0))
  1.0  === pow( 0, 0.0)
  0.0  === pow( 0, 1.0)
  0.0  === pow( 0, 2.0)
@@ -61,25 +61,25 @@ FALSE ===@pow( 0,-1.0)
  1.0  === pow( 2, 0.0)
  2.0  === pow( 2, 1.0)
  4.0  === pow( 2, 2.0)
- 2147483648 ~== pow(2,31)
+ 2147483648 === pow(2,31)
 -2147483648 ~== pow(-2,31)
  1000000000 === pow(10,9)
  100000000  === pow(-10,8)
  1    === pow(-1,1443279822)
 -1    === pow(-1,1443279821)
 sqrt(2) ~== pow(2,1/2)
-FALSE ===@pow(-2.0,-2.0)
-FALSE ===@pow(-2.0,-1.0)
-FALSE ===@pow(-2.0, 0.0)
-FALSE ===@pow(-2.0, 1.0)
-FALSE ===@pow(-2.0, 2.0)
-FALSE ===@pow(-1.0,-2.0)
-FALSE ===@pow(-1.0,-1.0)
-FALSE ===@pow(-1.0, 0.0)
-FALSE ===@pow(-1.0, 1.0)
-FALSE ===@pow(-1.0, 2.0)
-FALSE ===@pow( 0.0,-2.0)
-FALSE ===@pow( 0.0,-1.0)
+ 0.25 === pow(-2.0,-2.0)
+-0.5  === pow(-2.0,-1.0)
+ 1.0  === pow(-2.0, 0.0)
+-2.0  === pow(-2.0, 1.0)
+ 4.0  === pow(-2.0, 2.0)
+ 1.0  === pow(-1.0,-2.0)
+-1.0  === pow(-1.0,-1.0)
+ 1.0  === pow(-1.0, 0.0)
+-1.0  === pow(-1.0, 1.0)
+ 1.0  === pow(-1.0, 2.0)
+ TRUE === isinf(pow(0.0,-2.0))
+ TRUE === isinf(pow(0.0,-1.0))
  1.0  === pow( 0.0, 0.0)
  0.0  === pow( 0.0, 1.0)
  0.0  === pow( 0.0, 2.0)
@@ -103,8 +103,8 @@ FALSE ===@pow( 0.0,-1.0)
  1.0  === pow(-1.0, 0)
 -1.0  === pow(-1.0, 1)
  1.0  === pow(-1.0, 2)
-FALSE ===@pow( 0.0,-2)
-FALSE ===@pow( 0.0,-1)
+ TRUE === isinf(pow( 0.0,-2))
+ TRUE === isinf(pow( 0.0,-1))
  1.0  === pow( 0.0, 0)
  0.0  === pow( 0.0, 1)
  0.0  === pow( 0.0, 2)
@@ -122,18 +122,18 @@ LONG_MAX-1 === pow(LONG_MAX-1,1)
 LONG_MIN+1 === pow(LONG_MIN+1,1)
 (LONG_MAX-1)*(LONG_MAX-1) ~== pow(LONG_MAX-1,2)
 (LONG_MIN+1)*(LONG_MIN+1) ~== pow(LONG_MIN+1,2)
-(float)(LONG_MAX-1) ~== pow(LONG_MAX-1,1.0)
-FALSE ===@pow(LONG_MIN+1,1.0)
+(float)(LONG_MAX-1) === pow(LONG_MAX-1,1.0)
+(float)(LONG_MIN+1) === pow(LONG_MIN+1,1.0)
 (LONG_MAX-1)*(LONG_MAX-1) ~== pow(LONG_MAX-1,2.0)
-FALSE ===@pow(LONG_MIN+1,2.0)
+(LONG_MIN+1)*(LONG_MIN+1) ~== pow(LONG_MIN+1,2.0)
 LONG_MAX === pow(LONG_MAX,1)
-LONG_MIN ~== pow(LONG_MIN,1)
+LONG_MIN === pow(LONG_MIN,1)
 LONG_MAX*LONG_MAX ~== pow(LONG_MAX,2)
 LONG_MIN*LONG_MIN ~== pow(LONG_MIN,2)
-(float)LONG_MAX ~== pow(LONG_MAX,1.0)
-FALSE ===@pow(LONG_MIN,1.0)
+(float)LONG_MAX === pow(LONG_MAX,1.0)
+(float)LONG_MIN === pow(LONG_MIN,1.0)
 LONG_MAX*LONG_MAX ~== pow(LONG_MAX,2.0)
-FALSE ===@pow(LONG_MIN,2.0)
+LONG_MIN*LONG_MIN ~== pow(LONG_MIN,2.0)
 TESTS;
 
  echo "On failure, please mail result to php-dev@lists.php.net\n";