Example #1
0
 /**
  * @param DecimalValue $margin
  * @param int $roundingExponent
  *
  * @return string|null Text
  */
 private function formatMargin(DecimalValue $margin, $roundingExponent)
 {
     if ($this->options->getOption(self::OPT_SHOW_UNCERTAINTY_MARGIN)) {
         // TODO: never round to 0! See bug #56892
         $roundedMargin = $this->decimalMath->roundToExponent($margin, $roundingExponent);
         if (!$roundedMargin->isZero()) {
             return $this->decimalFormatter->format($roundedMargin);
         }
     }
     return null;
 }
Example #2
0
 /**
  * @dataProvider shiftProvider
  */
 public function testShift(DecimalValue $value, $exponent, $expected)
 {
     $math = new DecimalMath();
     $actual = $math->shift($value, $exponent);
     $this->assertEquals($expected, $actual->getValue());
 }
Example #3
0
 /**
  * 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);
 }
Example #4
0
 /**
  * Returns a transformed value derived from this QuantityValue by applying
  * the given transformation to the amount and the upper and lower bounds.
  * The resulting amount and bounds are rounded to the significant number of
  * digits. Note that for exact quantities (with at least one bound equal to
  * the amount), no rounding is applied (since they are considered to have
  * infinite precision).
  *
  * The transformation is provided as a callback, which must implement a
  * monotonously increasing, fully differentiable function mapping a DecimalValue
  * to a DecimalValue. Typically, it will be a linear transformation applying a
  * factor and an offset.
  *
  * @param string $newUnit The unit of the transformed quantity.
  *
  * @param callable $transformation A callback that implements the desired transformation.
  *        The transformation will be called three times, once for the amount, once
  *        for the lower bound, and once for the upper bound. It must return a DecimalValue.
  *        The first parameter passed to $transformation is the DecimalValue to transform
  *        In addition, any extra parameters passed to transform() will be passed through
  *        to the transformation callback.
  *
  * @param mixed ... Any extra parameters will be passed to the $transformation function.
  *
  * @throws InvalidArgumentException
  * @return QuantityValue
  */
 public function transform($newUnit, $transformation)
 {
     if (!is_callable($transformation)) {
         throw new InvalidArgumentException('$transformation must be callable.');
     }
     if (!is_string($newUnit)) {
         throw new InvalidArgumentException('$newUnit must be a string. Use "1" as the unit for unit-less quantities.');
     }
     if ($newUnit === '') {
         throw new InvalidArgumentException('$newUnit must not be empty. Use "1" as the unit for unit-less quantities.');
     }
     $oldUnit = $this->getUnit();
     if ($newUnit === null) {
         $newUnit = $oldUnit;
     }
     // Apply transformation by calling the $transform callback.
     // The first argument for the callback is the DataValue to transform. In addition,
     // any extra arguments given for transform() are passed through.
     $args = func_get_args();
     array_shift($args);
     $args[0] = $this->getAmount();
     $amount = call_user_func_array($transformation, $args);
     $args[0] = $this->getUpperBound();
     $upperBound = call_user_func_array($transformation, $args);
     $args[0] = $this->getLowerBound();
     $lowerBound = call_user_func_array($transformation, $args);
     // use a preliminary QuantityValue to determine the significant number of digits
     $transformed = new self($amount, $newUnit, $upperBound, $lowerBound);
     $roundingExponent = $transformed->getOrderOfUncertainty();
     // apply rounding to the significant digits
     $math = new DecimalMath();
     $amount = $math->roundToExponent($amount, $roundingExponent);
     $upperBound = $math->roundToExponent($upperBound, $roundingExponent);
     $lowerBound = $math->roundToExponent($lowerBound, $roundingExponent);
     return new self($amount, $newUnit, $upperBound, $lowerBound);
 }