Daniel Werner has submitted this change and it was merged.
Change subject: Introducing DecimalMath
......................................................................
Introducing DecimalMath
This adds functionality for doing basic arithemetics, rounding, etc
on DecimalValue objects. This is useful for automatically determining
precision/uncertainty based on the number of digits given, and ultimately,
for unit conversion.
Change-Id: Idc3006d7e0f5fd635233a3de57b8194f76f4b434
---
M DataValuesCommon/DataValuesCommon.classes.php
A DataValuesCommon/src/DataValues/DecimalMath.php
M DataValuesCommon/src/DataValues/DecimalValue.php
A DataValuesCommon/tests/DataValues/DecimalMathTest.php
M DataValuesCommon/tests/DataValues/DecimalValueTest.php
5 files changed, 626 insertions(+), 3 deletions(-)
Approvals:
Daniel Werner: Looks good to me, approved
jenkins-bot: Verified
diff --git a/DataValuesCommon/DataValuesCommon.classes.php
b/DataValuesCommon/DataValuesCommon.classes.php
index 277c744..7dbd1a6 100644
--- a/DataValuesCommon/DataValuesCommon.classes.php
+++ b/DataValuesCommon/DataValuesCommon.classes.php
@@ -54,6 +54,7 @@
'DataValues\LatLongValue' => 'src/DataValues/LatLongValue.php',
'DataValues\MonolingualTextValue' =>
'src/DataValues/MonolingualTextValue.php',
'DataValues\MultilingualTextValue' =>
'src/DataValues/MultilingualTextValue.php',
+ 'DataValues\DecimalMath' => 'src/DataValues/DecimalMath.php',
'DataValues\DecimalValue' => 'src/DataValues/DecimalValue.php',
'DataValues\QuantityValue' => 'src/DataValues/QuantityValue.php',
'DataValues\TimeValue' => 'src/DataValues/TimeValue.php',
diff --git a/DataValuesCommon/src/DataValues/DecimalMath.php
b/DataValuesCommon/src/DataValues/DecimalMath.php
new file mode 100644
index 0000000..ccbd664
--- /dev/null
+++ b/DataValuesCommon/src/DataValues/DecimalMath.php
@@ -0,0 +1,319 @@
+<?php
+
+namespace DataValues;
+
+/**
+ * Class for performing basic arithmetic and other transformations
+ * on DecimalValues.
+ *
+ * @see DecimalValue
+ *
+ * @since 0.1
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+class DecimalMath {
+
+ /**
+ * Returns the product of the two values.
+ *
+ * @param DecimalValue $a
+ * @param DecimalValue $b
+ *
+ * @return DecimalValue
+ */
+ public function product( DecimalValue $a, DecimalValue $b ) {
+ //TODO: use bcmath if available
+ $product = $a->getValueFloat() * $b->getValueFloat();
+
+ return new DecimalValue( $product );
+ }
+
+ /**
+ * Returns the sum of the two values.
+ *
+ * @param DecimalValue $a
+ * @param DecimalValue $b
+ *
+ * @return DecimalValue
+ */
+ public function sum( DecimalValue $a, DecimalValue $b ) {
+ //TODO: use bcmath if available
+ $product = $a->getValueFloat() + $b->getValueFloat();
+
+ return new DecimalValue( $product );
+ }
+
+ /**
+ * Returns the given value, with any insignificant digits removed or
zeroed.
+ * Rounding is applied using the "round half away from zero" rule
(that is, +0.5 is
+ * rounded to +1 and -0.5 is rounded to -1).
+ *
+ * @since 0.1
+ *
+ * @param DecimalValue $decimal
+ * @param int $significantDigits
+ *
+ * @throws \InvalidArgumentException
+ * @return DecimalValue
+ */
+ public function round( DecimalValue $decimal, $significantDigits ) {
+ $value = $decimal->getValue();
+ $rounded = $this->roundDigits( $value, $significantDigits );
+ return new DecimalValue( $rounded );
+ }
+
+ /**
+ * Returns the given value, with any insignificant digits removed or
zeroed.
+ * Rounding is applied using the "round half away from zero" rule (that
is, +0.5 is
+ * rounded to +1 and -0.5 is rounded to -1).
+ *
+ * @see round()
+ *
+ * @param string $value
+ * @param int $significantDigits
+ *
+ * @throws \InvalidArgumentException
+ * @return string
+ */
+ protected function roundDigits( $value, $significantDigits ) {
+ if ( !is_int( $significantDigits ) ) {
+ throw new \InvalidArgumentException(
'$significantDigits must be an integer' );
+ }
+
+ if ( $significantDigits <= 0 ) {
+ throw new \InvalidArgumentException(
'$significantDigits must be larger than zero.' );
+ }
+
+ // whether the last character is already part of the integer
part of the decimal value
+ $inIntPart = ( strpos( $value, '.' ) === false );
+
+ $rounded = '';
+
+ // Iterate over characters from right to left and build the
result back to front.
+ for ( $i = strlen( $value ) -1; $i > 0 && $i >
$significantDigits; $i-- ) {
+
+ list( $value, $i, $inIntPart, $next ) =
$this->roundNextDigit( $value, $i, $inIntPart );
+
+ $rounded = $next . $rounded;
+ }
+
+ // just keep the remainder of the value as is (this includes
the sign)
+ $rounded = substr( $value, 0, $i +1 ) . $rounded;
+
+ // strip trailing decimal point
+ $rounded = rtrim( $rounded, '.' );
+ return $rounded;
+ }
+
+ /**
+ * Extracts the next character to add to the result of a rounding run:
+ * $value[$] will be examined and processed in order to determine the
next
+ * character to prepend to the result (returned in the $nextCharacter
field).
+ *
+ * Updated values for the parameters are returned as well as the next
+ * character.
+ *
+ * @param string $value
+ * @param int $i
+ * @param bool $inIntPart
+ *
+ * @return array ( $value, $i, $inIntPart, $nextCharacter )
+ */
+ private function roundNextDigit( $value, $i, $inIntPart ) {
+ // next digit
+ $ch = $value[$i];
+
+ if ( $ch === '.' ) {
+ // just transition from the fractional to the integer
part
+ $inIntPart = true;
+ $nextCharacter = '.';
+ } else {
+ if ( $inIntPart ) {
+ // in the integer part, zero out insignificant
digits
+ $nextCharacter = '0';
+ } else {
+ // in the fractional part, strip insignificant
digits
+ $nextCharacter = '';
+ }
+
+ if ( ord( $ch ) >= ord( '5' ) ) {
+ // when stripping a character >= 5, bump up the
next digit to the left.
+ list( $value, $i, $inIntPart ) =
$this->bumpDigitsForRounding( $value, $i, $inIntPart );
+ }
+ }
+
+ return array( $value, $i, $inIntPart, $nextCharacter );
+ }
+
+ /**
+ * Bumps the last digit of a value that is being processed for rounding
while taking
+ * care of edge cases and updating the state of the rounding process.
+ *
+ * - $value is truncated to $i digits, so we can safely increment
(bump) the last digit.
+ * - if the last character of $value is '.', it's trimmed (and
$inIntPart is set to true)
+ * to handle the transition from the fractional to the integer part
of $value.
+ * - the last digit of $value is bumped using bumpDigits() - this is
where the magic happens.
+ * - $i is set to strln( $value ) to make the index consistent in case
a trailing decimal
+ * point got removed.
+ *
+ * Updated values for the parameters are returned.
+ * Note: when returning, $i is always one greater than the greatest
valid index in $value.
+ *
+ * @param string $value
+ * @param int $i
+ * @param bool $inIntPart
+ *
+ * @return array ( $value, $i, $inIntPart, $next )
+ */
+ private function bumpDigitsForRounding( $value, $i, $inIntPart ) {
+ $remaining = substr( $value, 0, $i );
+
+ // If there's a '.' at the end, strip it and note that we are
in the
+ // integer part of $value now.
+ if ( $remaining[ strlen( $remaining ) -1 ] === '.' ) {
+ $remaining = rtrim( $remaining, '.' );
+ $inIntPart = true;
+ }
+
+ // Rounding may add digits, adjust $i for that.
+ $value = $this->bumpDigits( $remaining );
+ $i = strlen( $value );
+
+ return array( $value, $i, $inIntPart );
+ }
+
+ /**
+ * Increment the least significant digit by one if it is less than 9,
and
+ * set it to zero and continue to the next more significant digit if it
is 9.
+ * Exception: bump( 0 ) == 1;
+ *
+ * E.g.: bump( 0.2 ) == 0.3, bump( -0.09 ) == -0.10, bump( 9.99 ) ==
10.00
+ *
+ * This is the inverse of @see slump()
+ *
+ * @since 0.1
+ *
+ * @param DecimalValue $decimal
+ *
+ * @return DecimalValue
+ */
+ public function bump( DecimalValue $decimal ) {
+ $value = $decimal->getValue();
+ $bumped = $this->bumpDigits( $value );
+ return new DecimalValue( $bumped );
+ }
+
+ /**
+ * Increment the least significant digit by one if it is less than 9,
and
+ * set it to zero and continue to the next more significant digit if it
is 9.
+ *
+ * @see bump()
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function bumpDigits( $value ) {
+ if ( $value === '+0' ) {
+ return '+1';
+ }
+
+ $bumped = '';
+
+ for ( $i = strlen( $value ) -1; $i >= 0; $i-- ) {
+ $ch = $value[$i];
+
+ if ( $ch === '.' ) {
+ $bumped = '.' . $bumped;
+ continue;
+ } elseif ( $ch === '9' ) {
+ $bumped = '0' . $bumped;
+ continue;
+ } elseif ( $ch === '+' || $ch === '-' ) {
+ $bumped = $ch . '1' . $bumped;
+ break;
+ } else {
+ $bumped = chr( ord( $ch ) + 1 ) . $bumped;
+ break;
+ }
+ }
+
+ $bumped = substr( $value, 0, $i ) . $bumped;
+ return $bumped;
+ }
+
+ /**
+ * Decrement the least significant digit by one if it is more than 0,
and
+ * set it to 9 and continue to the next more significant digit if it is
0.
+ * Exception: slump( 0 ) == -1;
+ *
+ * E.g.: slump( 0.2 ) == 0.1, slump( -0.10 ) == -0.01, slump( 0.0 ) ==
-1.0
+ *
+ * This is the inverse of @see bump()
+ *
+ * @since 0.1
+ *
+ * @param DecimalValue $decimal
+ *
+ * @return DecimalValue
+ */
+ public function slump( DecimalValue $decimal ) {
+ $value = $decimal->getValue();
+ $slumped = $this->slumpDigits( $value );
+ return new DecimalValue( $slumped );
+ }
+
+ /**
+ * Decrement the least significant digit by one if it is more than 0,
and
+ * set it to 9 and continue to the next more significant digit if it is
0.
+ *
+ * @see slump()
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function slumpDigits( $value ) {
+ if ( $value === '+0' ) {
+ return '-1';
+ }
+
+ // a "precise zero" will become negative
+ if ( preg_match( '/^\+0\.(0*)0$/', $value, $m ) ) {
+ return '-0.' . $m[1] . '1';
+ }
+
+ $slumped = '';
+
+ for ( $i = strlen( $value ) -1; $i >= 0; $i-- ) {
+ $ch = substr( $value, $i, 1 );
+
+ if ( $ch === '.' ) {
+ $slumped = '.' . $slumped;
+ continue;
+ } elseif ( $ch === '0' ) {
+ $slumped = '9' . $slumped;
+ continue;
+ } elseif ( $ch === '+' || $ch === '-' ) {
+ $slumped = '0';
+ break;
+ } else {
+ $slumped = chr( ord( $ch ) - 1 ) . $slumped;
+ break;
+ }
+ }
+
+ // preserve prefix
+ $slumped = substr( $value, 0, $i ) . $slumped;
+
+ // strip leading zeros
+ $slumped = preg_replace( '/^([-+])(0+)([0-9]+(\.|$))/', '\1\3',
$slumped );
+
+ if ( $slumped === '-0' ) {
+ $slumped = '+0';
+ }
+
+ return $slumped;
+ }
+
+}
\ No newline at end of file
diff --git a/DataValuesCommon/src/DataValues/DecimalValue.php
b/DataValuesCommon/src/DataValues/DecimalValue.php
index dea0203..6db74b5 100644
--- a/DataValuesCommon/src/DataValues/DecimalValue.php
+++ b/DataValuesCommon/src/DataValues/DecimalValue.php
@@ -263,6 +263,37 @@
}
/**
+ * Determines whether this DecimalValue is zero.
+ *
+ * @return bool
+ */
+ public function isZero() {
+ return (bool)preg_match( '/^[-+]0+(\.0+)?$/', $this->value );
+ }
+
+ /**
+ * Returns a new DecimalValue that represents the complement of this
DecimalValue.
+ * That is, it constructs a new DecimalValue with the same digits as
this,
+ * but with the sign inverted.
+ *
+ * Note that if isZero() returns true, this method returns this
+ * DecimalValue itself (because zero is it's own complement).
+ *
+ * @return DecimalValue
+ */
+ public function computeComplement() {
+ if ( $this->isZero() ) {
+ return $this;
+ }
+
+ $sign = $this->getSign();
+ $invertedSign = ( $sign === '+' ? '-' : '+' );
+
+ $inverseDigits = $invertedSign . substr( $this->value, 1 );
+ return new DecimalValue( $inverseDigits );
+ }
+
+ /**
* Returns the integer part of the value, that is, the part before the
decimal point,
* without the sign.
*
diff --git a/DataValuesCommon/tests/DataValues/DecimalMathTest.php
b/DataValuesCommon/tests/DataValues/DecimalMathTest.php
new file mode 100644
index 0000000..4156b93
--- /dev/null
+++ b/DataValuesCommon/tests/DataValues/DecimalMathTest.php
@@ -0,0 +1,230 @@
+<?php
+
+namespace DataValues\Tests;
+
+use DataValues\DecimalMath;
+use DataValues\DecimalValue;
+
+/**
+ * @covers DataValues\DecimalMathTest
+ *
+ * @since 0.1
+ *
+ * @group DataValue
+ * @group DataValueExtensions
+ *
+ * @licence GNU GPL v2+
+ *
+ * @author Daniel Kinzler
+ */
+class DecimalMathTest extends \PHPUnit_Framework_TestCase {
+
+ /**
+ * @dataProvider bumpProvider
+ *
+ * @since 0.1
+ */
+ public function testBump( DecimalValue $value, $expected ) {
+ $math = new DecimalMath();
+ $actual = $math->bump( $value );
+ $this->assertSame( $expected, $actual->getValue() );
+ }
+
+ public function bumpProvider() {
+ return array(
+ array( new DecimalValue( '+0' ), '+1' ),
+ array( new DecimalValue( '-0' ), '+1' ),
+ array( new DecimalValue( '+0.0' ), '+0.1' ),
+ array( new DecimalValue( '-0.0' ), '+0.1' ),
+ array( new DecimalValue( '+1' ), '+2' ),
+ array( new DecimalValue( '-1' ), '-2' ),
+ array( new DecimalValue( '+10' ), '+11' ),
+ array( new DecimalValue( '-10' ), '-11' ),
+ array( new DecimalValue( '+9' ), '+10' ),
+ array( new DecimalValue( '-9' ), '-10' ),
+ array( new DecimalValue( '+0.01' ), '+0.02' ),
+ array( new DecimalValue( '-0.01' ), '-0.02' ),
+ array( new DecimalValue( '+0.09' ), '+0.10' ),
+ array( new DecimalValue( '-0.09' ), '-0.10' ),
+ array( new DecimalValue( '+0.9' ), '+1.0' ),
+ array( new DecimalValue( '-0.9' ), '-1.0' ),
+ );
+ }
+
+ /**
+ * @dataProvider slumpProvider
+ *
+ * @since 0.1
+ */
+ public function testSlump( DecimalValue $value, $expected ) {
+ $math = new DecimalMath();
+ $actual = $math->slump( $value );
+ $this->assertSame( $expected, $actual->getValue() );
+ }
+
+ public function slumpProvider() {
+ return array(
+ array( new DecimalValue( '+0' ), '-1' ),
+ array( new DecimalValue( '-0' ), '-1' ),
+ array( new DecimalValue( '+0.0' ), '-0.1' ),
+ array( new DecimalValue( '-0.0' ), '-0.1' ),
+ array( new DecimalValue( '+0.00' ), '-0.01' ),
+ array( new DecimalValue( '-0.00' ), '-0.01' ),
+ array( new DecimalValue( '+1' ), '+0' ),
+ array( new DecimalValue( '-1' ), '+0' ),
+ array( new DecimalValue( '+1.0' ), '+0.9' ),
+ array( new DecimalValue( '-1.0' ), '-0.9' ),
+ array( new DecimalValue( '+0.1' ), '+0.0' ),
+ array( new DecimalValue( '-0.1' ), '+0.0' ), // zero
is always normalized to be positive
+ array( new DecimalValue( '+0.01' ), '+0.00' ),
+ array( new DecimalValue( '-0.01' ), '+0.00' ), // zero
is always normalized to be positive
+ array( new DecimalValue( '+12' ), '+11' ),
+ array( new DecimalValue( '-12' ), '-11' ),
+ array( new DecimalValue( '+10' ), '+9' ),
+ array( new DecimalValue( '-10' ), '-9' ),
+ array( new DecimalValue('+100' ), '+99' ),
+ array( new DecimalValue('-100' ), '-99' ),
+ array( new DecimalValue( '+0.02' ), '+0.01' ),
+ array( new DecimalValue( '-0.02' ), '-0.01' ),
+ array( new DecimalValue( '+0.10' ), '+0.09' ),
+ array( new DecimalValue( '-0.10' ), '-0.09' ),
+ );
+ }
+
+ /**
+ * @dataProvider productProvider
+ */
+ public function testProduct( DecimalValue $a, DecimalValue $b, $value )
{
+ $math = new DecimalMath();
+
+ $actual = $math->product( $a, $b );
+ $this->assertEquals( $value, $actual->getValue() );
+
+ $actual = $math->product( $b, $a );
+ $this->assertEquals( $value, $actual->getValue() );
+ }
+
+ public function productProvider() {
+ return array(
+ array( new DecimalValue( '+0' ), new DecimalValue(
'+0' ), '+0' ),
+ array( new DecimalValue( '+0' ), new DecimalValue(
'+1' ), '+0' ),
+ array( new DecimalValue( '+0' ), new DecimalValue(
'+2' ), '+0' ),
+
+ array( new DecimalValue( '+1' ), new DecimalValue(
'+0' ), '+0' ),
+ array( new DecimalValue( '+1' ), new DecimalValue(
'+1' ), '+1' ),
+ array( new DecimalValue( '+1' ), new DecimalValue(
'+2' ), '+2' ),
+
+ array( new DecimalValue( '+2' ), new DecimalValue(
'+0' ), '+0' ),
+ array( new DecimalValue( '+2' ), new DecimalValue(
'+1' ), '+2' ),
+ array( new DecimalValue( '+2' ), new DecimalValue(
'+2' ), '+4' ),
+
+ array( new DecimalValue( '+0.5' ), new DecimalValue(
'+0' ), '+0' ),
+ array( new DecimalValue( '+0.5' ), new DecimalValue(
'+1' ), '+0.5' ),
+ array( new DecimalValue( '+0.5' ), new DecimalValue(
'+2' ), '+1' ),
+ );
+ }
+
+ /**
+ * @dataProvider sumProvider
+ */
+ public function testSum( DecimalValue $a, DecimalValue $b, $value ) {
+ $math = new DecimalMath();
+
+ $actual = $math->sum( $a, $b );
+ $this->assertEquals( $value, $actual->getValue() );
+
+ $actual = $math->sum( $b, $a );
+ $this->assertEquals( $value, $actual->getValue() );
+ }
+
+ public function sumProvider() {
+ return array(
+ array( new DecimalValue( '+0' ), new DecimalValue(
'+0' ), '+0' ),
+ array( new DecimalValue( '+0' ), new DecimalValue(
'+1' ), '+1' ),
+ array( new DecimalValue( '+0' ), new DecimalValue(
'+2' ), '+2' ),
+
+ array( new DecimalValue( '+2' ), new DecimalValue(
'+0' ), '+2' ),
+ array( new DecimalValue( '+2' ), new DecimalValue(
'+1' ), '+3' ),
+ array( new DecimalValue( '+2' ), new DecimalValue(
'+2' ), '+4' ),
+
+ array( new DecimalValue( '+0.5' ), new DecimalValue(
'+0' ), '+0.5' ),
+ array( new DecimalValue( '+0.5' ), new DecimalValue(
'+0.5' ), '+1.0' ),
+ array( new DecimalValue( '+0.5' ), new DecimalValue(
'+2' ), '+2.5' ),
+ );
+ }
+
+ /**
+ * @dataProvider roundProvider
+ *
+ * @since 0.1
+ */
+ public function testRound( DecimalValue $value, $digits, $expected ) {
+ $math = new DecimalMath();
+
+ $actual = $math->round( $value, $digits );
+ $this->assertSame( $expected, $actual->getValue() );
+ }
+
+ public function roundProvider() {
+ $argLists = array();
+
+ //NOTE: Rounding is applied using the "round half away from
zero" logic.
+
+ $argLists[] = array( new DecimalValue( '+0' ), 1, '+0' );
+ $argLists[] = array( new DecimalValue( '+0' ), 2, '+0' );
+ $argLists[] = array( new DecimalValue( '+0.0' ), 1, '+0' );
+ $argLists[] = array( new DecimalValue( '+0.0' ), 2, '+0' );
+ $argLists[] = array( new DecimalValue( '+0.0' ), 3, '+0.0' );
+
+ $argLists[] = array( new DecimalValue( '-2' ), 1, '-2' );
+ $argLists[] = array( new DecimalValue( '-2' ), 2, '-2' );
+
+ $argLists[] = array( new DecimalValue( '+23' ), 1, '+20' );
+ $argLists[] = array( new DecimalValue( '+23' ), 2, '+23' );
+ $argLists[] = array( new DecimalValue( '+23' ), 3, '+23' );
+
+ $argLists[] = array( new DecimalValue( '-234' ), 1, '-200' );
+ $argLists[] = array( new DecimalValue( '-234' ), 2, '-230' );
+ $argLists[] = array( new DecimalValue( '-234' ), 3, '-234' );
+
+ $argLists[] = array( new DecimalValue( '-2.0' ), 1, '-2' );
+ $argLists[] = array( new DecimalValue( '-2.0' ), 2, '-2' );
// edge case, may change
+ $argLists[] = array( new DecimalValue( '-2.0' ), 3, '-2.0' );
+ $argLists[] = array( new DecimalValue( '-2.0' ), 4, '-2.0' );
// edge case, may change
+
+ $argLists[] = array( new DecimalValue( '-2.000' ), 1, '-2' );
+ $argLists[] = array( new DecimalValue( '-2.000' ), 2, '-2' );
+ $argLists[] = array( new DecimalValue( '-2.000' ), 3, '-2.0' );
+ $argLists[] = array( new DecimalValue( '-2.000' ), 4, '-2.00' );
+
+ $argLists[] = array( new DecimalValue( '+2.5' ), 1, '+3' ); //
rounded up
+ $argLists[] = array( new DecimalValue( '+2.5' ), 2, '+3' );
+ $argLists[] = array( new DecimalValue( '+2.5' ), 3, '+2.5' );
+ $argLists[] = array( new DecimalValue( '+2.5' ), 4, '+2.5' );
+
+ $argLists[] = array( new DecimalValue( '+2.05' ), 1, '+2' );
+ $argLists[] = array( new DecimalValue( '+2.05' ), 2, '+2' );
+ $argLists[] = array( new DecimalValue( '+2.05' ), 3, '+2.1' );
// rounded up
+ $argLists[] = array( new DecimalValue( '+2.05' ), 4, '+2.05' );
+
+ $argLists[] = array( new DecimalValue( '-23.05' ), 1, '-20' );
+ $argLists[] = array( new DecimalValue( '-23.05' ), 2, '-23' );
+ $argLists[] = array( new DecimalValue( '-23.05' ), 3, '-23' );
// edge case, may change
+ $argLists[] = array( new DecimalValue( '-23.05' ), 4, '-23.1'
); // rounded down
+ $argLists[] = array( new DecimalValue( '-23.05' ), 5, '-23.05'
);
+
+ $argLists[] = array( new DecimalValue( '+9.33' ), 1, '+9' ); //
no rounding
+ $argLists[] = array( new DecimalValue( '+9.87' ), 1, '+10' );
// rounding ripples up
+ $argLists[] = array( new DecimalValue( '+9.87' ), 3, '+9.9' );
// rounding ripples up
+ $argLists[] = array( new DecimalValue( '+99' ), 1, '+100' ); //
rounding ripples up
+ $argLists[] = array( new DecimalValue( '+99' ), 2, '+99' ); //
rounding ripples up
+
+ $argLists[] = array( new DecimalValue( '-9.33' ), 1, '-9' ); //
no rounding
+ $argLists[] = array( new DecimalValue( '-9.87' ), 1, '-10' );
// rounding ripples down
+ $argLists[] = array( new DecimalValue( '-9.87' ), 3, '-9.9' );
// rounding ripples down
+ $argLists[] = array( new DecimalValue( '-99' ), 1, '-100' ); //
rounding ripples down
+ $argLists[] = array( new DecimalValue( '-99' ), 2, '-99' ); //
rounding ripples down
+
+ return $argLists;
+ }
+}
diff --git a/DataValuesCommon/tests/DataValues/DecimalValueTest.php
b/DataValuesCommon/tests/DataValues/DecimalValueTest.php
index 763d93c..4a8e685 100644
--- a/DataValuesCommon/tests/DataValues/DecimalValueTest.php
+++ b/DataValuesCommon/tests/DataValues/DecimalValueTest.php
@@ -9,8 +9,6 @@
*
* @since 0.1
*
- * @ingroup DataValue
- *
* @group DataValue
* @group DataValueExtensions
*
@@ -247,4 +245,48 @@
array( new DecimalValue( '+0.01' ), '01' ),
);
}
-}
+
+ /**
+ * @dataProvider computeComplementProvider
+ *
+ * @since 0.1
+ */
+ public function testInverse( DecimalValue $value, $expected ) {
+ $complement = $value->computeComplement();
+ $this->assertSame( $expected, $complement->getValue() );
+
+ $actual = $complement->computeComplement();
+ $this->assertSame( $value->getValue(), $actual->getValue() );
+ }
+
+ public function computeComplementProvider() {
+ return array(
+ array( new DecimalValue( '+0' ), '+0' ),
+ array( new DecimalValue( '+0.00' ), '+0.00' ),
+ array( new DecimalValue( '+1' ), '-1' ),
+ array( new DecimalValue( '+100.663' ), '-100.663' ),
+ array( new DecimalValue( '-0.001' ), '+0.001' ),
+ );
+ }
+
+ /**
+ * @dataProvider isZeroProvider
+ *
+ * @since 0.1
+ */
+ public function testIsZero( DecimalValue $value, $expected ) {
+ $actual = $value->isZero();
+ $this->assertSame( $expected, $actual );
+ }
+
+ public function isZeroProvider() {
+ return array(
+ array( new DecimalValue( '+0' ), true ),
+ array( new DecimalValue( '-0.00' ), true ),
+
+ array( new DecimalValue( '+1' ), false ),
+ array( new DecimalValue( '+100.663' ), false ),
+ array( new DecimalValue( '-0.001' ), false ),
+ );
+ }
+}
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/89717
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Idc3006d7e0f5fd635233a3de57b8194f76f4b434
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Addshore <[email protected]>
Gerrit-Reviewer: Aude <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Daniel Werner <[email protected]>
Gerrit-Reviewer: Jeroen De Dauw <[email protected]>
Gerrit-Reviewer: Tobias Gritschacher <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits