Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
92.31% covered (success)
92.31%
12 / 13
CRAP
98.61% covered (success)
98.61%
71 / 72
BcMathCalculator
0.00% covered (danger)
0.00%
0 / 1
92.31% covered (success)
92.31%
12 / 13
30
98.61% covered (success)
98.61%
71 / 72
 __construct
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
2 / 2
 supported
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 compare
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 add
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 subtract
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 multiply
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 divide
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 ceil
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
6 / 6
 floor
100.00% covered (success)
100.00%
1 / 1
3
100.00% covered (success)
100.00%
6 / 6
 absolute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
 round
0.00% covered (danger)
0.00%
0 / 1
13
97.73% covered (success)
97.73%
43 / 44
 roundDigit
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
6 / 6
 share
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
1 / 1
<?php
namespace Money\Calculator;
use Money\Calculator;
use Money\Money;
use Money\Number;
/**
 * @author Frederik Bosch <f.bosch@genkgo.nl>
 */
final class BcMathCalculator implements Calculator
{
    /**
     * @var string
     */
    private $scale;
    /**
     * @param int $scale
     */
    public function __construct($scale = 14)
    {
        $this->scale = $scale;
    }
    /**
     * {@inheritdoc}
     */
    public static function supported()
    {
        return extension_loaded('bcmath');
    }
    /**
     * {@inheritdoc}
     */
    public function compare($a, $b)
    {
        return bccomp($a, $b, $this->scale);
    }
    /**
     * {@inheritdoc}
     */
    public function add($amount, $addend)
    {
        return bcadd($amount, $addend, 0);
    }
    /**
     * {@inheritdoc}
     *
     * @param $amount
     * @param $subtrahend
     *
     * @return string
     */
    public function subtract($amount, $subtrahend)
    {
        return bcsub($amount, $subtrahend, 0);
    }
    /**
     * {@inheritdoc}
     */
    public function multiply($amount, $multiplier)
    {
        return bcmul($amount, $multiplier, $this->scale);
    }
    /**
     * {@inheritdoc}
     */
    public function divide($amount, $divisor)
    {
        return bcdiv($amount, $divisor, $this->scale);
    }
    /**
     * {@inheritdoc}
     */
    public function ceil($number)
    {
        $number = Number::fromString((string) $number);
        if ($number->isDecimal() === false) {
            return (string) $number;
        }
        if ($number->isNegative() === true) {
            return bcadd((string) $number, '0', 0);
        }
        return bcadd((string) $number, '1', 0);
    }
    /**
     * {@inheritdoc}
     */
    public function floor($number)
    {
        $number = Number::fromString((string) $number);
        if ($number->isDecimal() === false) {
            return (string) $number;
        }
        if ($number->isNegative() === true) {
            return bcadd((string) $number, '-1', 0);
        }
        return bcadd($number, '0', 0);
    }
    /**
     * {@inheritdoc}
     */
    public function absolute($number)
    {
        return ltrim($number, '-');
    }
    /**
     * {@inheritdoc}
     */
    public function round($number, $roundingMode)
    {
        $number = Number::fromString((string) $number);
        if ($number->isDecimal() === false) {
            return (string) $number;
        }
        if ($number->isHalf() === false) {
            return $this->roundDigit($number);
        }
        if (Money::ROUND_HALF_UP === $roundingMode) {
            return bcadd(
                (string) $number,
                $number->getIntegerRoundingMultiplier(),
                0
            );
        }
        if (Money::ROUND_HALF_DOWN === $roundingMode) {
            return bcadd((string) $number, '0', 0);
        }
        if (Money::ROUND_HALF_EVEN === $roundingMode) {
            if ($number->isCurrentEven() === true) {
                return bcadd((string) $number, '0', 0);
            }
            return bcadd(
                (string) $number,
                $number->getIntegerRoundingMultiplier(),
                0
            );
        }
        if (Money::ROUND_HALF_ODD === $roundingMode) {
            if ($number->isCurrentEven() === true) {
                return bcadd(
                    (string) $number,
                    $number->getIntegerRoundingMultiplier(),
                    0
                );
            }
            return bcadd((string) $number, '0', 0);
        }
        if (Money::ROUND_HALF_POSITIVE_INFINITY === $roundingMode) {
            if ($number->isNegative() === true) {
                return bcadd((string) $number, '0', 0);
            }
            return bcadd(
                (string) $number,
                $number->getIntegerRoundingMultiplier(),
                0
            );
        }
        if (Money::ROUND_HALF_NEGATIVE_INFINITY === $roundingMode) {
            if ($number->isNegative() === true) {
                return bcadd(
                    (string) $number,
                    $number->getIntegerRoundingMultiplier(),
                    0
                );
            }
            return bcadd(
                (string) $number,
                '0',
                0
            );
        }
        throw new \InvalidArgumentException('Unknown rounding mode');
    }
    /**
     * @param $number
     *
     * @return string
     */
    private function roundDigit(Number $number)
    {
        if ($number->isCloserToNext()) {
            return bcadd(
                (string) $number,
                $number->getIntegerRoundingMultiplier(),
                0
            );
        }
        return bcadd((string) $number, '0', 0);
    }
    /**
     * {@inheritdoc}
     */
    public function share($amount, $ratio, $total)
    {
        return $this->floor(bcdiv(bcmul($amount, $ratio, $this->scale), $total, $this->scale));
    }
}