public function matchBest($value, $pos = 7) { /* * Have to use this instead of scalar type hints. Because we are dealing with arbitrarily large numbers, we are * using the bc math extension. This means that all numbers are actually strings in order to retain precision. * * If we used the int or float type hints, PHP 7 would cast string values (which is good), but that would lose * precision in the cast (which is bad). * * is_numeric will achieve the desired effect without altering the $value */ if (!is_numeric($value)) { throw new \Exception('Cannot pass a non-numeric value.'); } // The number is more than three orders of magnitude from zero if ($value >= 1000 || $value <= -1000) { // Increase the exponent by three and try again return $this->matchBest(MathProvider::divide($value, 1000), $pos + 1); } // The number is a decimal less than one from zero if ($value < 1 && $value > -1 && $value != 0) { // Decrease the exponent by three and try again return $this->matchBest(MathProvider::multiply($value, 1000), $pos - 1); } // If no transformation is needed, we have a special case of the return if ($pos == 7) { return ['value' => $value, 'scale' => '1', 'prefix' => '']; } // Otherwise, we have our answer return ['value' => $value, 'scale' => $this->scale[$this->order[$pos]], 'prefix' => $this->order[$pos]]; }
/** * @param Length $distance * @param Acceleration $acceleration * @param UnitComposition|null $unitComposition * * @return Time */ public static function timeFromConstantAccel(Length $distance, Acceleration $acceleration, UnitComposition $unitComposition = null) { if (is_null($unitComposition)) { $unitComposition = new UnitComposition(); } $distance->toNative(); $acceleration->toNative(); return new Time(MathProvider::squareRoot(MathProvider::multipleMultiply(2, $distance->getValue(), $acceleration->getValue())), $unitComposition); }
public function subtract(Quantity $quantity) { if (get_class($this) != get_class($quantity)) { throw new \Exception('Cannot subtract units of two different types.'); } $oldUnit = $quantity->getUnit(); $this->value = MathProvider::subtract($this->value, $quantity->to($this->unit)->getValue()); $quantity->to($oldUnit); return $this; }
/** * @param Quantity[] $mults * @param Quantity[] $divides * @param int $precision */ public function naiveMultiOpt(array $mults, array $divides, $precision = 2) { $newUnit = $this->getMultiUnits($mults, $divides); $newVal = 1; foreach ($mults as $quantity) { $newVal = MathProvider::multiply($newVal, $quantity->toNative()->getValue()); } foreach ($divides as $quantity) { $newVal = MathProvider::divide($newVal, $quantity->toNative()->getValue(), $precision); } return $newUnit->preConvertedAdd($newVal); }