Skip to content

Commit

Permalink
Fix signum of NAN and int conversion of specials
Browse files Browse the repository at this point in the history
  • Loading branch information
rtheunissen committed Feb 9, 2019
1 parent 4eaf2c3 commit b1e0162
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 14 deletions.
31 changes: 29 additions & 2 deletions php_decimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,22 @@ static void php_decimal_integer_overflow()
zend_throw_exception(spl_ce_OverflowException, "Integer overflow", 0);
}

/**
* Called when NaN or Inf is converted to integer.
*/
void php_decimal_integer_from_special_is_not_defined()
{
zend_throw_exception(spl_ce_RuntimeException, "Converting NaN or Inf to integer is not defined", 0);
}

/**
* Called when attempting to query the signum of NaN.
*/
void php_decimal_sign_of_nan_is_not_defined()
{
zend_throw_exception(spl_ce_RuntimeException, "Sign of NaN is not defined", 0);
}

/**
* Called when __construct is called directly on a decimal object.
*/
Expand Down Expand Up @@ -777,8 +793,9 @@ static zend_long php_decimal_to_long(php_decimal_t *obj)
uint32_t status = 0;
zend_long result = 0;

/* This matches PHP's behaviour. */
/* PHP converts to zero but that does not make sense and could hide bugs. */
if (UNEXPECTED(mpd_isspecial(mpd))) {
php_decimal_integer_from_special_is_not_defined();
return 0;
}

Expand Down Expand Up @@ -883,6 +900,16 @@ static zend_string *php_decimal_format(php_decimal_t *obj, zend_long places, zen
/* OPERATIONS */
/******************************************************************************/

static int php_decimal_signum(const mpd_t *mpd)
{
if (UNEXPECTED(mpd_isnan(mpd))) {
php_decimal_sign_of_nan_is_not_defined();
return 0;
}

return mpd_iszero(mpd) ? 0 : mpd_arith_sign(mpd);
}

/**
* Sets the result of res to op1 + op2, using the precision of res.
*
Expand Down Expand Up @@ -2086,7 +2113,7 @@ PHP_DECIMAL_ARGINFO_END()
PHP_DECIMAL_METHOD(signum)
{
PHP_DECIMAL_PARAMS_PARSE_NONE();
RETURN_LONG(mpd_iszero(THIS_MPD()) ? 0 : mpd_arith_sign(THIS_MPD()));
RETURN_LONG(php_decimal_signum(THIS_MPD()));
}

/**
Expand Down
37 changes: 27 additions & 10 deletions tests/cast.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ $tests = [
[(int) decimal(PHP_INT_MAX), PHP_INT_MAX],
[(int) decimal(PHP_INT_MIN), PHP_INT_MIN],

[(int) decimal( NAN), 0],
[(int) decimal( INF), 0],
[(int) decimal(-INF), 0],

/**
* FLOAT
*/
Expand Down Expand Up @@ -92,23 +88,44 @@ foreach ($tests as $test) {
try {
(int) decimal("1E+1000");
} catch (OverflowException $e) {
printf("%s\n", $e->getMessage());
printf("A %s\n", $e->getMessage());
}

try {
(float) decimal("1E-1000");
} catch (UnderflowException $e) {
printf("%s\n", $e->getMessage());
printf("B %s\n", $e->getMessage());
}

try {
(float) decimal("-1E-1000");
} catch (UnderflowException $e) {
printf("%s\n", $e->getMessage());
printf("C %s\n", $e->getMessage());
}

try {
(int) decimal(NAN);
} catch (RuntimeException $e) {
printf("D %s\n", $e->getMessage());
}

try {
(int) decimal(INF);
} catch (RuntimeException $e) {
printf("E %s\n", $e->getMessage());
}

try {
(int) decimal(-INF);
} catch (RuntimeException $e) {
printf("F %s\n", $e->getMessage());
}

?>
--EXPECT--
Integer overflow
Floating point underflow
Floating point underflow
A Integer overflow
B Floating point underflow
C Floating point underflow
D Converting NaN or Inf to integer is not defined
E Converting NaN or Inf to integer is not defined
F Converting NaN or Inf to integer is not defined
10 changes: 8 additions & 2 deletions tests/methods/signum.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,15 @@ var_dump(decimal("1234.5678E-9")->signum());
var_dump(decimal("-1234.5678E+9")->signum());
var_dump(decimal("-1234.5678E-9")->signum());

var_dump(decimal( "NAN")->signum());
var_dump(decimal( "INF")->signum());
var_dump(decimal("-INF")->signum());

try {
decimal("NAN")->signum();
} catch (RuntimeException $e) {
printf("%s\n", $e->getMessage());
}

?>
--EXPECT--
int(0)
Expand All @@ -36,5 +42,5 @@ int(1)
int(-1)
int(-1)
int(1)
int(1)
int(-1)
Sign of NaN is not defined
3 changes: 3 additions & 0 deletions tests/methods/toInt.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ if ((string) $number !== "2.5") {

?>
--EXPECT--
RuntimeException: Converting NaN or Inf to integer is not defined
RuntimeException: Converting NaN or Inf to integer is not defined
RuntimeException: Converting NaN or Inf to integer is not defined
OverflowException: Integer overflow
TypeError: Decimal\Decimal::__construct() expected parameter 1 to be a string, integer, or decimal, float given
TypeError: Decimal\Decimal::__construct() expected parameter 1 to be a string, integer, or decimal, float given

0 comments on commit b1e0162

Please sign in to comment.