php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #15811 pow() in 4.1.2
Submitted: 2002-03-01 10:23 UTC Modified: 2002-03-01 15:42 UTC
From: jbriss at utk dot edu Assigned:
Status: Closed Package: *Math Functions
PHP Version: 4.1.2 OS: linux redhat
Private report: No CVE-ID: None
 [2002-03-01 10:23 UTC] jbriss at utk dot edu
function pow()
in version  4.0.6 function pow(0,x),x!=0 always returns 0.
in version 4.1.2 function pow(0,x) x!=0 always returns nan, i think that is not correct. 

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2002-03-01 10:25 UTC] derick@php.net
It's fixed for 4.2.0 already:

[derick@kossu dev]$ php
<?php
echo pow (0, 80);
?>
X-Powered-By: PHP/4.2.0-dev
Content-type: text/html

0



Derick
 [2002-03-01 14:28 UTC] jbriss at utk dot edu
i looked little bit to your function pow (in math.c) and added some comments make sure you fixed it also for exponent type double. 

PHP_FUNCTION(pow)
{
	/* 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 (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;
		}
/* !!!!!!!!!!!!!!!!!!!! Here you are missing part of the code  */
		RETURN_DOUBLE(exp(log(Z_DVAL_PP(zbase)) * Z_DVAL_PP(zexp)));
/* !!!!!!!!!!!!!!!!!!!! It should look like  */
                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 { 
         		RETURN_DOUBLE(exp(log(Z_DVAL_PP(zbase)) * Z_DVAL_PP(zexp)));
		}

	  }

/* !!!!!!!!!!!!!!!!!!!! This is an end, please look at the end */

	/* pow(?, int), this is the ** case */

	lexp = Z_LVAL_PP(zexp);


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

			/* 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;
			}
/* !!!!!!!!!!!!!!!!!!!! This is nice that you want to return integer when possible,
  but this is probably the slowest algorithm you could use */
			/* return */
	}
}
 [2002-03-01 15:42 UTC] jimw@php.net
this function was rewritten completely in the 4.2/HEAD branch. (it's now about eight times shorter, and actually correct.)
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Sat Aug 13 18:05:44 2022 UTC