From d7c2c8248d8e84fb49664c1dbad683f7a8d3864c Mon Sep 17 00:00:00 2001 From: Marius Hoch Date: Tue, 30 Mar 2021 15:15:58 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20DecimalMath::productWithoutBC=20for=20val?= =?UTF-8?q?ues=20larger=20than=202^63=E2=88=921?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- README.md | 6 +++++- src/DataValues/DecimalMath.php | 4 ++-- tests/DataValues/DecimalMathTest.php | 28 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 197ee20..383eb4c 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/src/DataValues/DecimalMath.php b/src/DataValues/DecimalMath.php index c25a6ce..5c0f17a 100644 --- a/src/DataValues/DecimalMath.php +++ b/src/DataValues/DecimalMath.php @@ -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 ); diff --git a/tests/DataValues/DecimalMathTest.php b/tests/DataValues/DecimalMathTest.php index 0e8a04d..f171e52 100644 --- a/tests/DataValues/DecimalMathTest.php +++ b/tests/DataValues/DecimalMathTest.php @@ -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 */