/** * @see ValueFormatter::format * * @since 0.1 * * @param DecimalValue $dataValue * * @throws InvalidArgumentException * @return string Text */ public function format($dataValue) { if (!$dataValue instanceof DecimalValue) { throw new InvalidArgumentException('Data value type mismatch. Expected a DecimalValue.'); } // TODO: Implement optional rounding/padding $decimal = $dataValue->getValue(); if (!$this->getOption(self::OPT_FORCE_SIGN)) { // strip leading + $decimal = ltrim($decimal, '+'); } // apply number localization $decimal = $this->localizer->localizeNumber($decimal); return $decimal; }
/** * 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); }
/** * 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); }
/** * Returns a QuantityValue representing the given amount, automatically assuming * a level of uncertainty based on the digits given. * * The upper and lower bounds are determined automatically from the given * digits by increasing resp. decreasing the least significant digit. * E.g. "+0.01" would have upperBound "+0.02" and lowerBound "+0.01", * while "-100" would have upperBound "-99" and lowerBound "-101". * * @param DecimalValue $amount The quantity * @param string $unit The quantity's unit (use "1" for unit-less quantities) * @param int $exponent Decimal exponent to apply * * @return QuantityValue */ private function newUncertainQuantityFromDigits(DecimalValue $amount, $unit = '1', $exponent = 0) { $math = new DecimalMath(); if ($amount->getSign() === '+') { $upperBound = $math->bump($amount); $lowerBound = $math->slump($amount); } else { $upperBound = $math->slump($amount); $lowerBound = $math->bump($amount); } $amount = $this->decimalParser->applyDecimalExponent($amount, $exponent); $lowerBound = $this->decimalParser->applyDecimalExponent($lowerBound, $exponent); $upperBound = $this->decimalParser->applyDecimalExponent($upperBound, $exponent); return new QuantityValue($amount, $unit, $upperBound, $lowerBound); }
/** * @dataProvider isZeroProvider */ public function testIsZero(DecimalValue $value, $expected) { $actual = $value->isZero(); $this->assertSame($expected, $actual); }
/** * @dataProvider applyDecimalExponentProvider */ public function testApplyDecimalExponent(DecimalValue $decimal, $exponent, DecimalValue $expectedDecimal) { $parser = new DecimalParser(); $actualDecimal = $parser->applyDecimalExponent($decimal, $exponent); $this->assertSame($expectedDecimal->getValue(), $actualDecimal->getValue()); }
/** * Constructs a new instance of the DataValue from the provided data. * This can round-trip with @see getArrayValue * * @since 0.1 * * @param mixed $data * * @return QuantityValue * @throws IllegalValueException */ public static function newFromArray($data) { self::requireArrayFields($data, array('amount', 'unit', 'upperBound', 'lowerBound')); return new static(DecimalValue::newFromArray($data['amount']), $data['unit'], DecimalValue::newFromArray($data['upperBound']), DecimalValue::newFromArray($data['lowerBound'])); }