/** * Shift the decimal point according to the given exponent. * * @param DecimalValue $decimal * @param int $exponent The exponent to apply (digits to shift by). A Positive exponent * shifts the decimal point to the right, a negative exponent shifts to the left. * * @throws InvalidArgumentException * @return DecimalValue */ public function shift(DecimalValue $decimal, $exponent) { if (!is_int($exponent)) { throw new InvalidArgumentException('$exponent must be an integer'); } if ($exponent == 0) { return $decimal; } $sign = $decimal->getSign(); $intPart = $decimal->getIntegerPart(); $fractPart = $decimal->getFractionalPart(); if ($exponent < 0) { $intPart = $this->shiftLeft($intPart, $exponent); } else { $fractPart = $this->shiftRight($fractPart, $exponent); } $digits = $sign . $intPart . $fractPart; $digits = $this->stripLeadingZeros($digits); return new DecimalValue($digits); }
/** * Compares this DecimalValue to another DecimalValue. * * @since 0.1 * * @param DecimalValue $that * * @throws LogicException * @return int +1 if $this > $that, 0 if $this == $that, -1 if $this < $that */ public function compare(DecimalValue $that) { if ($this === $that) { return 0; } $a = $this->getValue(); $b = $that->getValue(); if ($a === $b) { return 0; } if ($a[0] === '+' && $b[0] === '-') { return 1; } if ($a[0] === '-' && $b[0] === '+') { return -1; } // compare the integer parts $aInt = ltrim($this->getIntegerPart(), '0'); $bInt = ltrim($that->getIntegerPart(), '0'); $sense = $a[0] === '+' ? 1 : -1; // per precondition, there are no leading zeros, so the longer nummber is greater if (strlen($aInt) > strlen($bInt)) { return $sense; } if (strlen($aInt) < strlen($bInt)) { return -$sense; } // if both have equal length, compare alphanumerically $cmp = strcmp($aInt, $bInt); if ($cmp > 0) { return $sense; } if ($cmp < 0) { return -$sense; } // compare fractional parts $aFract = rtrim($this->getFractionalPart(), '0'); $bFract = rtrim($that->getFractionalPart(), '0'); // the fractional part is left-aligned, so just check alphanumeric ordering $cmp = strcmp($aFract, $bFract); return $cmp > 0 ? $sense : ($cmp < 0 ? -$sense : 0); }
/** * @dataProvider getGetIntegerPartProvider */ public function testGetFractionalPart(DecimalValue $value, $expected) { $actual = $value->getIntegerPart(); $this->assertSame($expected, $actual); }