Skip to content

Commit

Permalink
Treat "-0" as "0"
Browse files Browse the repository at this point in the history
"0" and "-0" are mathematically identical so it should they should
treated as the same value.

Zero is considered neither positive nor negative, so `isPositive()` and
`isNegative()` both return `false`. This is consistent with `signum()`.
  • Loading branch information
julienfalque committed Feb 21, 2022
1 parent cd36614 commit de3e771
Show file tree
Hide file tree
Showing 39 changed files with 168 additions and 14 deletions.
44 changes: 39 additions & 5 deletions php_decimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,17 @@ static void php_decimal_set_nan(php_decimal_t *obj)
php_decimal_mpd_set_nan(PHP_DECIMAL_MPD(obj));
}

/**
* Sets the value to "0" in case it is "-0"
*/
static void php_decimal_prevent_negative_zero(mpd_t *mpd)
{
if (mpd_iszero(mpd) && mpd_isnegative(mpd)) {
uint32_t status = 0;
mpd_qcopy_negate(mpd, mpd, &status);
}
}

/**
* Parses a string to a given precision. Trailing zeroes are not preserved.
*/
Expand All @@ -617,6 +628,8 @@ static php_success_t php_decimal_mpd_set_string(mpd_t *mpd, zend_string *str, ze
php_decimal_loss_of_data_on_string_conversion();
}

php_decimal_prevent_negative_zero(mpd);

return SUCCESS;
}

Expand Down Expand Up @@ -1157,12 +1170,16 @@ static void php_decimal_ceil(php_decimal_t *res, mpd_t *op1)
*/
static void php_decimal_truncate(php_decimal_t *res, mpd_t *op1)
{
mpd_t *mpd = PHP_DECIMAL_MPD(res);
uint32_t status = 0;

if (mpd_isspecial(op1)) {
mpd_qcopy(PHP_DECIMAL_MPD(res), op1, &status);
mpd_qcopy(mpd, op1, &status);
return;
}
mpd_qtrunc(PHP_DECIMAL_MPD(res), op1, php_decimal_context(), &status);

mpd_qtrunc(mpd, op1, php_decimal_context(), &status);
php_decimal_prevent_negative_zero(mpd);
}

/**
Expand Down Expand Up @@ -1197,6 +1214,12 @@ static void php_decimal_abs(php_decimal_t *res, mpd_t *op1)
static void php_decimal_negate(php_decimal_t *res, mpd_t *op1)
{
uint32_t status = 0;

if (mpd_iszero(op1)) {
mpd_qcopy(PHP_DECIMAL_MPD(res), op1, &status);
return;
}

mpd_qcopy_negate(PHP_DECIMAL_MPD(res), op1, &status);
}

Expand Down Expand Up @@ -1433,6 +1456,8 @@ static void php_decimal_do_binary_op(php_decimal_binary_op_t op, php_decimal_t *
php_decimal_set_precision(res, prec);
op(res, mpd1, mpd2);
mpd_del(&tmp);

php_decimal_prevent_negative_zero(PHP_DECIMAL_MPD(res));
}


Expand Down Expand Up @@ -2201,7 +2226,10 @@ PHP_DECIMAL_METHOD(round)
#endif
ZEND_PARSE_PARAMETERS_END();

php_decimal_round_mpd(PHP_DECIMAL_MPD(res), PHP_DECIMAL_MPD(obj), places, rounding);
mpd_t *mpd = PHP_DECIMAL_MPD(res);
php_decimal_round_mpd(mpd, PHP_DECIMAL_MPD(obj), places, rounding);
php_decimal_prevent_negative_zero(mpd);

RETURN_DECIMAL(res);
}

Expand Down Expand Up @@ -2373,7 +2401,10 @@ PHP_DECIMAL_ARGINFO_END()
PHP_DECIMAL_METHOD(isPositive)
{
PHP_DECIMAL_PARAMS_PARSE_NONE();
RETURN_BOOL(mpd_ispositive(THIS_MPD()));

mpd_t *mpd = THIS_MPD();

RETURN_BOOL(!mpd_iszero(mpd) && mpd_ispositive(mpd));
}

/**
Expand All @@ -2384,7 +2415,10 @@ PHP_DECIMAL_ARGINFO_END()
PHP_DECIMAL_METHOD(isNegative)
{
PHP_DECIMAL_PARAMS_PARSE_NONE();
RETURN_BOOL(mpd_isnegative(THIS_MPD()));

mpd_t *mpd = THIS_MPD();

RETURN_BOOL(!mpd_iszero(mpd) && mpd_isnegative(mpd));
}

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/php7/cast.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ $tests = [
* STRING
*/
[(string) decimal(), "0"],
[(string) decimal("-0"), "-0"],
[(string) decimal("-0"), "0"],
[(string) decimal("5.2"), "5.2"],

[(string) decimal( "NAN"), "NAN"],
Expand Down
18 changes: 18 additions & 0 deletions tests/php7/clone.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ use Decimal\Decimal;
$a = new Decimal("1.234", 16);
$b = clone $a;

var_dump($a);
var_dump($b);

$a = new Decimal("-0");
$b = clone $a;

var_dump($a);
var_dump($b);
?>
Expand All @@ -27,3 +33,15 @@ object(Decimal\Decimal)#2 (2) {
["precision"]=>
int(16)
}
object(Decimal\Decimal)#3 (2) {
["value"]=>
string(1) "0"
["precision"]=>
int(28)
}
object(Decimal\Decimal)#1 (2) {
["value"]=>
string(1) "0"
["precision"]=>
int(28)
}
2 changes: 2 additions & 0 deletions tests/php7/empty.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use Decimal\Decimal;

var_dump(empty(new Decimal()));
var_dump(empty(new Decimal(0)));
var_dump(empty(new Decimal('-0')));
var_dump(empty(new Decimal(1)));

var_dump(empty(new Decimal( "1E-1000")));
Expand All @@ -28,3 +29,4 @@ bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
2 changes: 2 additions & 0 deletions tests/php7/json.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ if (!extension_loaded("json")) echo 'skip';
<?php
use Decimal\Decimal;

var_dump(json_encode(new Decimal("-0", 20)));
var_dump(json_encode(new Decimal("1.2345", 20)));
var_dump(json_encode(new Decimal("5.0000", 20)));
?>
--EXPECT--
string(3) ""0""
string(8) ""1.2345""
string(8) ""5.0000""
3 changes: 3 additions & 0 deletions tests/php7/methods/abs.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use Decimal\Decimal;
function decimal(...$args) { return new Decimal(...$args); }

$tests = [
["0", "0"],
["-0", "0"],

["-0.1", "0.1"],
["+0.1", "0.1"],
[ "0.1", "0.1"],
Expand Down
3 changes: 3 additions & 0 deletions tests/php7/methods/avg.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ $tests = [
[[array('-2.3', '4.1', 5), ], "2.266666666666666666666666667", 28],
[[array('-2.3', '4.1', 5), 10], "2.266666667", 10],
[[array('-2.3', '4.1', 5), 30], "2.26666666666666666666666666667", 30],

[[[decimal("0.1"), decimal("-0.1")]], "0.0", 28],
[[[decimal("-0.1"), decimal("0.1")]], "0.0", 28],
];

foreach ($tests as $index => $test) {
Expand Down
3 changes: 3 additions & 0 deletions tests/php7/methods/ceil.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use Decimal\Decimal;
function decimal(...$args) { return new Decimal(...$args); }

$tests = [
["0", "0"],
["-0", "0"],

["-0.1", "-0"],
[ "0.1", "1"],

Expand Down
5 changes: 5 additions & 0 deletions tests/php7/methods/compareTo.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ $tests = [
[decimal(), false, 1],
[decimal(), 0.0, 0],

[decimal("-0"), 0, 0],
[decimal("-0"), null, 1],
[decimal("-0"), false, 1],
[decimal("-0"), 0.0, 0],

[decimal(1), 0, 1],
[decimal(1), null, 1],
[decimal(1), false, 1],
Expand Down
17 changes: 17 additions & 0 deletions tests/php7/methods/copy.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ $dst = $src->copy();

var_dump($src, $dst);

$src = new Decimal\Decimal("-0", 32);
$dst = $src->copy();

var_dump($src, $dst);

?>
--EXPECT--
object(Decimal\Decimal)#1 (2) {
Expand All @@ -25,3 +30,15 @@ object(Decimal\Decimal)#2 (2) {
["precision"]=>
int(32)
}
object(Decimal\Decimal)#3 (2) {
["value"]=>
string(1) "0"
["precision"]=>
int(32)
}
object(Decimal\Decimal)#1 (2) {
["value"]=>
string(1) "0"
["precision"]=>
int(32)
}
11 changes: 11 additions & 0 deletions tests/php7/methods/div.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ $tests = [
[new Decimal("-INF"), "NAN", (string) (-INF / NAN), 28],
[new Decimal("-INF"), "INF", (string) (-INF / INF), 28],
[new Decimal("-INF"), "-INF", (string) (-INF / -INF), 28],

[
new Decimal("0"),
new Decimal("10"),
"0", 28
],
[
new Decimal("-0"),
new Decimal("10"),
"0", 28
],
];

foreach ($tests as $index => $test) {
Expand Down
2 changes: 2 additions & 0 deletions tests/php7/methods/equals.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ $tests = [
[decimal(1), 1.0, true],
[decimal(1), "1", true],

[decimal("-0"), 0, true],

[decimal("0.1"), 0.1, true],
[decimal("0.2"), 0.2, true],
[decimal("0.200"), 0.2, true],
Expand Down
3 changes: 3 additions & 0 deletions tests/php7/methods/exp.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use Decimal\Decimal;
function decimal(...$args) { return new Decimal(...$args); }

$tests = [
[decimal("0"), "1", 28],
[decimal("-0"), "1", 28],

[decimal("-0.1", 50), "0.90483741803595957316424905944643662119470536098040", 50],
[decimal( "0.1", 50), "1.1051709180756476248117078264902466682245471947375", 50],

Expand Down
3 changes: 3 additions & 0 deletions tests/php7/methods/floor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use Decimal\Decimal;
function decimal(...$args) { return new Decimal(...$args); }

$tests = [
["0", "0"],
["-0", "0"],

["-0.1", "-1"],
[ "0.1", "0"],

Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/isEven.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $tests = [
["-2.000000000000000000000000001", false], // not truncated

[0, true],
["-0", true],
[1, false],
[2, true],
[3, false],
Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/isInf.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $tests = [
["-1E-50", false],

[0, false],
["-0", false],
[1, false],
[2, false],
[3, false],
Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/isInteger.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $tests = [
["-1E-50", false],

[0, true],
["-0", true],
[1, true],
[2, true],
[3, true],
Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/isNaN.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $tests = [
["-1E-50", false],

[0, false],
["-0", false],
[1, false],
[2, false],
[3, false],
Expand Down
2 changes: 1 addition & 1 deletion tests/php7/methods/isNegative.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ $tests = [
["-1E-50", true],

["0", false],
["-0", true],
["-0", false],
[1, false],
[2, false],
[3, false],
Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/isOdd.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $tests = [
["-3.000000000000000000000000001", false], // not truncated

[0, false],
["-0", false],
[1, true],
[2, false],
[3, true],
Expand Down
2 changes: 1 addition & 1 deletion tests/php7/methods/isPositive.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ $tests = [
[ "1E-50", true],
["-1E-50", false],

["0", true],
["0", false],
["-0", false],
[1, true],
[2, true],
Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/isZero.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ $tests = [
["-1E-50", false],

[0, true],
["-0", true],
[1, false],
[2, false],
[3, false],
Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/ln.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ $tests = [
[decimal( "NAN"), (string) log( NAN), 28],
[decimal( "INF"), (string) log( INF), 28],
[decimal( "0"), (string) log( 0), 28],
[decimal( "-0"), (string) log( 0), 28],
[decimal( "-1"), (string) log( -1), 28],
];

Expand Down
1 change: 1 addition & 0 deletions tests/php7/methods/log10.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ $tests = [
[decimal( "NAN"), (string) log10( NAN), 28],
[decimal( "INF"), (string) log10( INF), 28],
[decimal( "0"), (string) log10( 0), 28],
[decimal( "-0"), (string) log10( 0), 28],
[decimal( "-1"), (string) log10( -1), 28],
];

Expand Down
2 changes: 2 additions & 0 deletions tests/php7/methods/mod.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ function decimal(...$args) { return new Decimal(...$args); }
$tests = [
[decimal("0"), "1", 0 % 1, 28],
[decimal("0"), "-1", 0 % -1, 28],
[decimal("-0"), "1", 0 % 1, 28],
[decimal("-0"), "-1", 0 % -1, 28],

[decimal( "1"), "3", 1 % 3, 28],
[decimal( "1"), "-3", 1 % -3, 28],
Expand Down
9 changes: 6 additions & 3 deletions tests/php7/methods/mul.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ $tests = [
[new Decimal( "NAN"), 0, "NAN", 28],
[new Decimal( "INF"), 0, "NAN", 28],
[new Decimal("-INF"), 0, "NAN", 28],

[new Decimal("0"), 2, "0", 28],
[new Decimal("-0"), 2, "0", 28],
];

foreach ($tests as $index => $test) {
Expand Down Expand Up @@ -122,8 +125,8 @@ Warning: Loss of data on string conversion in %s on line 24

Warning: Loss of data on string conversion in %s on line 25

Warning: Loss of data on integer conversion in %s on line 77
Warning: Loss of data on integer conversion in %s on line 80

Warning: Loss of data on integer conversion in %s on line 79
Warning: Loss of data on integer conversion in %s on line 82

Warning: Loss of data on integer conversion in %s on line 80
Warning: Loss of data on integer conversion in %s on line 83
Loading

0 comments on commit de3e771

Please sign in to comment.