mirror of
https://github.com/php/php-src.git
synced 2025-08-16 22:18:50 +02:00
Fixed pow(), and added finite(), isinf(), and isnan(). Also fixed
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.
This commit is contained in:
parent
4b8f435b2a
commit
461e105069
4 changed files with 112 additions and 137 deletions
|
@ -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)
|
||||
|
|
|
@ -382,117 +382,86 @@ PHP_FUNCTION(pi)
|
|||
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ proto bool finite(double val)
|
||||
Returns whether double is finite. */
|
||||
PHP_FUNCTION(finite)
|
||||
{
|
||||
double dval;
|
||||
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
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));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool isnan(double val)
|
||||
Returns whether double is not a number. */
|
||||
PHP_FUNCTION(isnan)
|
||||
{
|
||||
double dval;
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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;
|
||||
zval *zbase, *zexp;
|
||||
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()");
|
||||
zend_bool wantlong;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &zbase, &zexp) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
if (Z_TYPE_PP(zexp) == IS_DOUBLE) {
|
||||
/* pow(?, float), this is the ^^ case */
|
||||
convert_to_double_ex(zbase);
|
||||
/* go ahead and calculate things. */
|
||||
dval = pow(Z_DVAL_P(zbase),Z_DVAL_P(zexp));
|
||||
|
||||
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)));
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
/* return */
|
||||
}
|
||||
/* otherwise just return the double. */
|
||||
RETURN_DOUBLE(dval);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto float exp(float number)
|
||||
Returns e raised to the power of the number */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue