Skip to content

Commit

Permalink
Merge pull request #115 from frederikbosch/nextrelease
Browse files Browse the repository at this point in the history
Deal with integer limits, closes #111
  • Loading branch information
sagikazarmark committed Jan 4, 2016
2 parents bab91f5 + 5c3d462 commit b5126fa
Show file tree
Hide file tree
Showing 12 changed files with 1,098 additions and 136 deletions.
8 changes: 6 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@
},
"require-dev": {
"kriswallsmith/buzz": "~0.15",
"phpunit/phpunit": "^4.5"
"phpunit/phpunit": "^4.5",
"ext-bcmath": "*",
"ext-gmp": "*"
},
"suggest": {
"TheBigBrainsCompany/TbbcMoneyBundle": "Very complete Symfony2 bundle with support for Twig, Doctrine, Forms, ...",
"pink-tie/money-bundle": "Pink-Tie's Symfony2 integration with Money library",
"Sylius/SyliusMoneyBundle": "Sylius' Symfony2 integration with Money library"
"Sylius/SyliusMoneyBundle": "Sylius' Symfony2 integration with Money library",
"ext-bcmath": "Calculate without integer limits",
"ext-gmp": "Calculate without integer limits"
},
"autoload": {
"psr-4": {
Expand Down
98 changes: 98 additions & 0 deletions src/Calculator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<?php
namespace Money;

/**
* Calculator Interface
* @author Frederik Bosch
*/
interface Calculator
{

/**
* Returns whether the calculator is supported in
* the current server environment
*
* @return bool
*/
public static function supported();

/**
* Compare a to b
*
* @param int|string $a
* @param int|string $b
* @return int
*/
public function compare($a, $b);

/**
* Add added to amount
*
* @param int|string $amount
* @param int|string $addend
* @return int|string
*/
public function add($amount, $addend);

/**
* Subtract subtrahend from amount
* @param int|string $amount
* @param int|string $subtrahend
* @return int|string
*/
public function subtract($amount, $subtrahend);

/**
* Multiply amount with multiplier
*
* @param int|string $amount
* @param int|float $multiplier
* @return int|string
*/
public function multiply($amount, $multiplier);

/**
* Divide amount with divisor
*
* @param int|string $amount
* @param int|float $divisor
* @return int|string
*/
public function divide($amount, $divisor);

/**
* Round number to following integer
*
* @param int|string|float $number
* @return int|string
*/
public function ceil($number);

/**
* Round number to preceding integer
*
* @param int|string|float $number
* @return int|string
*/
public function floor($number);

/**
* Round number, use rounding mode for tie-breaker
*
* @param int|string|float $number
* @param int|string $roundingMode
* @return int|string
*/
public function round($number, $roundingMode);

/**
* Share amount among ratio / total portions
*
* @param int|string $amount
* @param int|float $ratio
* @param int|float $total
* @return int|string
*/
public function share($amount, $ratio, $total);

}
162 changes: 162 additions & 0 deletions src/Calculator/BcMathCalculator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
<?php
namespace Money\Calculator;

use Money\Calculator;
use Money\Money;
use Money\Number;

/**
* Class BcMathCalculator
* @package Money\Calculator
*/
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);
}

/**
* {@inheritdoc}
*/
public function add($amount, $addend)
{
return bcadd($amount, $addend);
}

/**
* {@inheritdoc}
*
* @param $amount
* @param $subtrahend
* @return string
*/
public function subtract($amount, $subtrahend)
{
return bcsub($amount, $subtrahend);
}

/**
* {@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)
{
$decimalSeparatorPosition = strpos($number, '.');
if ($decimalSeparatorPosition === false) {
return $number;
}

return bcadd($number, '1', 0);
}

/**
* {@inheritdoc}
*/
public function floor($number)
{
return bcadd($number, '0', 0);
}

/**
* {@inheritdoc}
*/
public function round($number, $roundingMode)
{
$number = new Number($number);
if ($number->isDecimal() === false) {
return (string) $number;
}

if ($number->isHalf() === false) {
return $this->roundDigit($number);
}

if ($roundingMode === Money::ROUND_HALF_DOWN) {
return $this->floor((string) $number);
}

if ($roundingMode === Money::ROUND_HALF_UP) {
return $this->ceil((string) $number);
}

if ($roundingMode === Money::ROUND_HALF_EVEN) {
if ($number->isCurrentEven() === true) {
return $this->floor((string) $number);
} else {
return $this->ceil((string) $number);
}
}

if ($roundingMode === Money::ROUND_HALF_ODD) {
if ($number->isCurrentEven() === true) {
return $this->ceil((string) $number);
} else {
return $this->floor((string) $number);
}
}

throw new \InvalidArgumentException('Unknown rounding mode');
}

/**
* @param $number
* @return string
*/
private function roundDigit(Number $number)
{
if ($number->isCloserToNext()) {
return $this->ceil((string) $number);
}

return $this->floor((string) $number);
}

/**
* {@inheritdoc}
*/
public function share($amount, $ratio, $total)
{
return $this->floor(bcdiv(bcmul($amount, $ratio, $this->scale), $total, $this->scale));
}

}
Loading

0 comments on commit b5126fa

Please sign in to comment.