Skip to content

Commit

Permalink
Fix DecimalMath::productWithoutBC for values larger than 2^63−1
Browse files Browse the repository at this point in the history
PHP switches to a exponential display if values are larger
than 2^63-1 (the maximum value of a signed 64 bit integer).

Fixes https://phabricator.wikimedia.org/T278824
  • Loading branch information
mariushoch committed Mar 30, 2021
1 parent bfedcbc commit d7c2c82
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 3 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,13 @@ the [Wikidata project](https://www.wikidata.org/).

## Release notes

### 0.11.1 (TBD)

* Fix `DecimalMath::productWithoutBC` for products larger than 2^63-1 (the maximum value of a signed 64 bit integer).

### 0.11.0 (2021-03-15)

* Drop support for php versions older than 7.2 and HHVM
* Drop support for php versions older than 7.2 and HHVM

### 0.10.2 (2021-03-15)

Expand Down
4 changes: 2 additions & 2 deletions src/DataValues/DecimalMath.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ private function productWithBC( DecimalValue $a, DecimalValue $b ) {
private function productWithoutBC( DecimalValue $a, DecimalValue $b ) {
$product = $a->getValueFloat() * $b->getValueFloat();

// Append .0 for consistency, if the result is a whole number,
// Add a decimal digit (.0) for consistency, if the result is a whole number,
// but $a or $b were specified with decimal places.
if (
$product === floor( $product ) &&
$a->getFractionalPart() . $b->getFractionalPart() !== ''
) {
$product = strval( $product ) . '.0';
$product = ( new DecimalValue( $product ) )->getValue() . '.0';
}

return new DecimalValue( $product );
Expand Down
28 changes: 28 additions & 0 deletions tests/DataValues/DecimalMathTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,34 @@ public function productProvider() {
}
}

/**
* @dataProvider productLargeFloatProvider
*/
public function testProductLargeFloat( $useBC, DecimalValue $a, DecimalValue $b, $regex ) {
$math = new DecimalMath( $useBC );

$actual = $math->product( $a, $b );
$this->assertRegExp( $regex, $actual->getValue() );

$actual = $math->product( $b, $a );
$this->assertRegExp( $regex, $actual->getValue() );
}

public function productLargeFloatProvider() {
$cases = [
[
new DecimalValue( '+1600000000000000000000000000000000000000000000' ),
new DecimalValue( '123.45' ),
'/^\+1975200000000000\d{32}\.\d+$/'
],
];

foreach ( $cases as $case ) {
yield array_merge( [ true ], $case );
yield array_merge( [ false ], $case );
}
}

/**
* @dataProvider productWithBCProvider
*/
Expand Down

0 comments on commit d7c2c82

Please sign in to comment.