예제 #1
0
 /**
  * Returns the order of magnitude of the uncertainty as the exponent of
  * last significant digit in the amount-string. The value returned by this
  * is suitable for use with @see DecimalMath::roundToExponent().
  *
  * @example: if two digits after the decimal point are significant, this
  * returns -2.
  *
  * @example: if the last two digits before the decimal point are insignificant,
  * this returns 2.
  *
  * Note that this calculation assumes a symmetric uncertainty interval,
  * and can be misleading.
  *
  * @since 0.1
  *
  * @return int
  */
 public function getOrderOfUncertainty()
 {
     // the desired precision is given by the distance between the amount and
     // whatever is closer, the upper or lower bound.
     //TODO: use DecimalMath to avoid floating point errors!
     $amount = $this->getAmount()->getValueFloat();
     $upperBound = $this->getUpperBound()->getValueFloat();
     $lowerBound = $this->getLowerBound()->getValueFloat();
     $precision = min($amount - $lowerBound, $upperBound - $amount);
     if ($precision === 0.0) {
         // If there is no uncertainty, the order of uncertainty is a bit more than what we have digits for.
         return -strlen($this->amount->getFractionalPart());
     }
     // e.g. +/- 200 -> 2; +/- 0.02 -> -2
     // note: we really want floor( log10( $precision ) ), but have to account for
     // small errors made in the floating point operations above.
     // @todo: use bcmath (via DecimalMath) to avoid this if possible
     $orderOfUncertainty = floor(log10($precision + 5.0E-10));
     return (int) $orderOfUncertainty;
 }
예제 #2
0
 /**
  * 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);
 }
예제 #3
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);
 }