Skip to content

Commit b986902

Browse files
committed
Treat "-0" as "0"
"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()`.
1 parent 49cd96e commit b986902

39 files changed

+276
-12
lines changed

php_decimal.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,17 @@ static void php_decimal_set_nan(php_decimal_t *obj)
592592
php_decimal_mpd_set_nan(PHP_DECIMAL_MPD(obj));
593593
}
594594

595+
/**
596+
* Sets the value to "0" in case it is "-0"
597+
*/
598+
static void php_decimal_prevent_negative_zero(mpd_t *mpd)
599+
{
600+
if (mpd_iszero(mpd) && mpd_isnegative(mpd)) {
601+
uint32_t status = 0;
602+
mpd_qcopy_negate(mpd, mpd, &status);
603+
}
604+
}
605+
595606
/**
596607
* Parses a string to a given precision. Trailing zeroes are not preserved.
597608
*/
@@ -617,6 +628,8 @@ static php_success_t php_decimal_mpd_set_string(mpd_t *mpd, zend_string *str, ze
617628
php_decimal_loss_of_data_on_string_conversion();
618629
}
619630

631+
php_decimal_prevent_negative_zero(mpd);
632+
620633
return SUCCESS;
621634
}
622635

@@ -1157,12 +1170,16 @@ static void php_decimal_ceil(php_decimal_t *res, mpd_t *op1)
11571170
*/
11581171
static void php_decimal_truncate(php_decimal_t *res, mpd_t *op1)
11591172
{
1173+
mpd_t *mpd = PHP_DECIMAL_MPD(res);
11601174
uint32_t status = 0;
1175+
11611176
if (mpd_isspecial(op1)) {
1162-
mpd_qcopy(PHP_DECIMAL_MPD(res), op1, &status);
1177+
mpd_qcopy(mpd, op1, &status);
11631178
return;
11641179
}
1165-
mpd_qtrunc(PHP_DECIMAL_MPD(res), op1, php_decimal_context(), &status);
1180+
1181+
mpd_qtrunc(mpd, op1, php_decimal_context(), &status);
1182+
php_decimal_prevent_negative_zero(mpd);
11661183
}
11671184

11681185
/**
@@ -1197,6 +1214,12 @@ static void php_decimal_abs(php_decimal_t *res, mpd_t *op1)
11971214
static void php_decimal_negate(php_decimal_t *res, mpd_t *op1)
11981215
{
11991216
uint32_t status = 0;
1217+
1218+
if (mpd_iszero(op1)) {
1219+
mpd_qcopy(PHP_DECIMAL_MPD(res), op1, &status);
1220+
return;
1221+
}
1222+
12001223
mpd_qcopy_negate(PHP_DECIMAL_MPD(res), op1, &status);
12011224
}
12021225

@@ -1433,6 +1456,8 @@ static void php_decimal_do_binary_op(php_decimal_binary_op_t op, php_decimal_t *
14331456
php_decimal_set_precision(res, prec);
14341457
op(res, mpd1, mpd2);
14351458
mpd_del(&tmp);
1459+
1460+
php_decimal_prevent_negative_zero(PHP_DECIMAL_MPD(res));
14361461
}
14371462

14381463

@@ -2201,7 +2226,10 @@ PHP_DECIMAL_METHOD(round)
22012226
#endif
22022227
ZEND_PARSE_PARAMETERS_END();
22032228

2204-
php_decimal_round_mpd(PHP_DECIMAL_MPD(res), PHP_DECIMAL_MPD(obj), places, rounding);
2229+
mpd_t *mpd = PHP_DECIMAL_MPD(res);
2230+
php_decimal_round_mpd(mpd, PHP_DECIMAL_MPD(obj), places, rounding);
2231+
php_decimal_prevent_negative_zero(mpd);
2232+
22052233
RETURN_DECIMAL(res);
22062234
}
22072235

@@ -2373,7 +2401,10 @@ PHP_DECIMAL_ARGINFO_END()
23732401
PHP_DECIMAL_METHOD(isPositive)
23742402
{
23752403
PHP_DECIMAL_PARAMS_PARSE_NONE();
2376-
RETURN_BOOL(mpd_ispositive(THIS_MPD()));
2404+
2405+
mpd_t *mpd = THIS_MPD();
2406+
2407+
RETURN_BOOL(!mpd_iszero(mpd) && mpd_ispositive(mpd));
23772408
}
23782409

23792410
/**
@@ -2384,7 +2415,10 @@ PHP_DECIMAL_ARGINFO_END()
23842415
PHP_DECIMAL_METHOD(isNegative)
23852416
{
23862417
PHP_DECIMAL_PARAMS_PARSE_NONE();
2387-
RETURN_BOOL(mpd_isnegative(THIS_MPD()));
2418+
2419+
mpd_t *mpd = THIS_MPD();
2420+
2421+
RETURN_BOOL(!mpd_iszero(mpd) && mpd_isnegative(mpd));
23882422
}
23892423

23902424
/**

tests/php7/cast.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ $tests = [
1919
* STRING
2020
*/
2121
[(string) decimal(), "0"],
22-
[(string) decimal("-0"), "-0"],
22+
[(string) decimal("-0"), "0"],
2323
[(string) decimal("5.2"), "5.2"],
2424

2525
[(string) decimal( "NAN"), "NAN"],

tests/php7/clone.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ use Decimal\Decimal;
1111
$a = new Decimal("1.234", 16);
1212
$b = clone $a;
1313

14+
var_dump($a);
15+
var_dump($b);
16+
17+
$a = new Decimal("-0");
18+
$b = clone $a;
19+
1420
var_dump($a);
1521
var_dump($b);
1622
?>
@@ -27,3 +33,15 @@ object(Decimal\Decimal)#2 (2) {
2733
["precision"]=>
2834
int(16)
2935
}
36+
object(Decimal\Decimal)#3 (2) {
37+
["value"]=>
38+
string(1) "0"
39+
["precision"]=>
40+
int(28)
41+
}
42+
object(Decimal\Decimal)#1 (2) {
43+
["value"]=>
44+
string(1) "0"
45+
["precision"]=>
46+
int(28)
47+
}

tests/php7/empty.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use Decimal\Decimal;
1010

1111
var_dump(empty(new Decimal()));
1212
var_dump(empty(new Decimal(0)));
13+
var_dump(empty(new Decimal('-0')));
1314
var_dump(empty(new Decimal(1)));
1415

1516
var_dump(empty(new Decimal( "1E-1000")));
@@ -28,3 +29,4 @@ bool(false)
2829
bool(false)
2930
bool(false)
3031
bool(false)
32+
bool(false)

tests/php7/json.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ if (!extension_loaded("json")) echo 'skip';
99
<?php
1010
use Decimal\Decimal;
1111

12+
var_dump(json_encode(new Decimal("-0", 20)));
1213
var_dump(json_encode(new Decimal("1.2345", 20)));
1314
var_dump(json_encode(new Decimal("5.0000", 20)));
1415
?>
1516
--EXPECT--
17+
string(3) ""0""
1618
string(8) ""1.2345""
1719
string(8) ""5.0000""

tests/php7/methods/abs.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use Decimal\Decimal;
1414
function decimal(...$args) { return new Decimal(...$args); }
1515

1616
$tests = [
17+
["0", "0"],
18+
["-0", "0"],
19+
1720
["-0.1", "0.1"],
1821
["+0.1", "0.1"],
1922
[ "0.1", "0.1"],

tests/php7/methods/avg.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ $tests = [
3939
[[array('-2.3', '4.1', 5), ], "2.266666666666666666666666667", 28],
4040
[[array('-2.3', '4.1', 5), 10], "2.266666667", 10],
4141
[[array('-2.3', '4.1', 5), 30], "2.26666666666666666666666666667", 30],
42+
43+
[[[decimal("0.1"), decimal("-0.1")]], "0.0", 28],
44+
[[[decimal("-0.1"), decimal("0.1")]], "0.0", 28],
4245
];
4346

4447
foreach ($tests as $index => $test) {

tests/php7/methods/ceil.phpt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use Decimal\Decimal;
1414
function decimal(...$args) { return new Decimal(...$args); }
1515

1616
$tests = [
17+
["0", "0"],
18+
["-0", "0"],
19+
1720
["-0.1", "-0"],
1821
[ "0.1", "1"],
1922

tests/php7/methods/compareTo.phpt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ $tests = [
2929
[decimal(), false, 1],
3030
[decimal(), 0.0, 0],
3131

32+
[decimal("-0"), 0, 0],
33+
[decimal("-0"), null, 1],
34+
[decimal("-0"), false, 1],
35+
[decimal("-0"), 0.0, 0],
36+
3237
[decimal(1), 0, 1],
3338
[decimal(1), null, 1],
3439
[decimal(1), false, 1],

tests/php7/methods/copy.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ $dst = $src->copy();
1111

1212
var_dump($src, $dst);
1313

14+
$src = new Decimal\Decimal("-0", 32);
15+
$dst = $src->copy();
16+
17+
var_dump($src, $dst);
18+
1419
?>
1520
--EXPECT--
1621
object(Decimal\Decimal)#1 (2) {
@@ -25,3 +30,15 @@ object(Decimal\Decimal)#2 (2) {
2530
["precision"]=>
2631
int(32)
2732
}
33+
object(Decimal\Decimal)#3 (2) {
34+
["value"]=>
35+
string(1) "0"
36+
["precision"]=>
37+
int(32)
38+
}
39+
object(Decimal\Decimal)#1 (2) {
40+
["value"]=>
41+
string(1) "0"
42+
["precision"]=>
43+
int(32)
44+
}

0 commit comments

Comments
 (0)