Open Monograph Press  3.3.0
BcMathCalculator.php
1 <?php
2 
3 namespace Money\Calculator;
4 
6 use Money\Money;
7 use Money\Number;
8 
12 final class BcMathCalculator implements Calculator
13 {
17  private $scale;
18 
22  public function __construct($scale = 14)
23  {
24  $this->scale = $scale;
25  }
26 
30  public static function supported()
31  {
32  return extension_loaded('bcmath');
33  }
34 
38  public function compare($a, $b)
39  {
40  return bccomp($a, $b, $this->scale);
41  }
42 
46  public function add($amount, $addend)
47  {
48  return (string) Number::fromString(bcadd($amount, $addend, $this->scale));
49  }
50 
59  public function subtract($amount, $subtrahend)
60  {
61  return (string) Number::fromString(bcsub($amount, $subtrahend, $this->scale));
62  }
63 
67  public function multiply($amount, $multiplier)
68  {
69  $multiplier = Number::fromNumber($multiplier);
70 
71  return bcmul($amount, (string) $multiplier, $this->scale);
72  }
73 
77  public function divide($amount, $divisor)
78  {
79  $divisor = Number::fromNumber($divisor);
80 
81  return bcdiv($amount, (string) $divisor, $this->scale);
82  }
83 
87  public function ceil($number)
88  {
89  $number = Number::fromNumber($number);
90 
91  if ($number->isInteger()) {
92  return (string) $number;
93  }
94 
95  if ($number->isNegative()) {
96  return bcadd((string) $number, '0', 0);
97  }
98 
99  return bcadd((string) $number, '1', 0);
100  }
101 
105  public function floor($number)
106  {
107  $number = Number::fromNumber($number);
108 
109  if ($number->isInteger()) {
110  return (string) $number;
111  }
112 
113  if ($number->isNegative()) {
114  return bcadd((string) $number, '-1', 0);
115  }
116 
117  return bcadd($number, '0', 0);
118  }
119 
123  public function absolute($number)
124  {
125  return ltrim($number, '-');
126  }
127 
131  public function round($number, $roundingMode)
132  {
133  $number = Number::fromNumber($number);
134 
135  if ($number->isInteger()) {
136  return (string) $number;
137  }
138 
139  if ($number->isHalf() === false) {
140  return $this->roundDigit($number);
141  }
142 
143  if (Money::ROUND_HALF_UP === $roundingMode) {
144  return bcadd(
145  (string) $number,
146  $number->getIntegerRoundingMultiplier(),
147  0
148  );
149  }
150 
151  if (Money::ROUND_HALF_DOWN === $roundingMode) {
152  return bcadd((string) $number, '0', 0);
153  }
154 
155  if (Money::ROUND_HALF_EVEN === $roundingMode) {
156  if ($number->isCurrentEven()) {
157  return bcadd((string) $number, '0', 0);
158  }
159 
160  return bcadd(
161  (string) $number,
162  $number->getIntegerRoundingMultiplier(),
163  0
164  );
165  }
166 
167  if (Money::ROUND_HALF_ODD === $roundingMode) {
168  if ($number->isCurrentEven()) {
169  return bcadd(
170  (string) $number,
171  $number->getIntegerRoundingMultiplier(),
172  0
173  );
174  }
175 
176  return bcadd((string) $number, '0', 0);
177  }
178 
179  if (Money::ROUND_HALF_POSITIVE_INFINITY === $roundingMode) {
180  if ($number->isNegative()) {
181  return bcadd((string) $number, '0', 0);
182  }
183 
184  return bcadd(
185  (string) $number,
186  $number->getIntegerRoundingMultiplier(),
187  0
188  );
189  }
190 
191  if (Money::ROUND_HALF_NEGATIVE_INFINITY === $roundingMode) {
192  if ($number->isNegative()) {
193  return bcadd(
194  (string) $number,
195  $number->getIntegerRoundingMultiplier(),
196  0
197  );
198  }
199 
200  return bcadd(
201  (string) $number,
202  '0',
203  0
204  );
205  }
206 
207  throw new \InvalidArgumentException('Unknown rounding mode');
208  }
209 
215  private function roundDigit(Number $number)
216  {
217  if ($number->isCloserToNext()) {
218  return bcadd(
219  (string) $number,
220  $number->getIntegerRoundingMultiplier(),
221  0
222  );
223  }
224 
225  return bcadd((string) $number, '0', 0);
226  }
227 
231  public function share($amount, $ratio, $total)
232  {
233  return $this->floor(bcdiv(bcmul($amount, $ratio, $this->scale), $total, $this->scale));
234  }
235 
239  public function mod($amount, $divisor)
240  {
241  return bcmod($amount, $divisor);
242  }
243 }
Money\Money\ROUND_HALF_DOWN
const ROUND_HALF_DOWN
Definition: Money.php:22
Money\Money
Definition: Money.php:16
Money\Calculator\BcMathCalculator\supported
static supported()
Definition: BcMathCalculator.php:33
Money\Money\ROUND_HALF_NEGATIVE_INFINITY
const ROUND_HALF_NEGATIVE_INFINITY
Definition: Money.php:34
Money\Money\ROUND_HALF_ODD
const ROUND_HALF_ODD
Definition: Money.php:26
Money\Calculator
Definition: BcMathCalculator.php:3
Money\Calculator\BcMathCalculator\absolute
absolute($number)
Definition: BcMathCalculator.php:126
Money\Calculator\BcMathCalculator\subtract
subtract($amount, $subtrahend)
Definition: BcMathCalculator.php:62
Money\Calculator
Definition: Calculator.php:10
Money\Calculator\BcMathCalculator
Definition: BcMathCalculator.php:12
Money\Number
Definition: Number.php:10
Money\Number\fromNumber
static fromNumber($number)
Definition: Number.php:84
Money\Calculator\BcMathCalculator\floor
floor($number)
Definition: BcMathCalculator.php:108
Money\Calculator\BcMathCalculator\mod
mod($amount, $divisor)
Definition: BcMathCalculator.php:242
Money\Number\fromString
static fromString($number)
Definition: Number.php:52
Money\Calculator\BcMathCalculator\share
share($amount, $ratio, $total)
Definition: BcMathCalculator.php:234
Money\Money\ROUND_HALF_EVEN
const ROUND_HALF_EVEN
Definition: Money.php:24
Money\Number\isCloserToNext
isCloserToNext()
Definition: Number.php:138
Money\Calculator\BcMathCalculator\add
add($amount, $addend)
Definition: BcMathCalculator.php:49
Money\Money\ROUND_HALF_POSITIVE_INFINITY
const ROUND_HALF_POSITIVE_INFINITY
Definition: Money.php:32
Money\Calculator\BcMathCalculator\divide
divide($amount, $divisor)
Definition: BcMathCalculator.php:80
Money\Calculator\BcMathCalculator\multiply
multiply($amount, $multiplier)
Definition: BcMathCalculator.php:70
Money\Money\ROUND_HALF_UP
const ROUND_HALF_UP
Definition: Money.php:20
Money\Calculator\BcMathCalculator\ceil
ceil($number)
Definition: BcMathCalculator.php:90
Money\Calculator\BcMathCalculator\round
round($number, $roundingMode)
Definition: BcMathCalculator.php:134
Money\Calculator\BcMathCalculator\__construct
__construct($scale=14)
Definition: BcMathCalculator.php:25
Money\Number\isNegative
isNegative()
Definition: Number.php:162
Money\Number\isCurrentEven
isCurrentEven()
Definition: Number.php:128
Money\Number\isInteger
isInteger()
Definition: Number.php:112
Money\Calculator\BcMathCalculator\compare
compare($a, $b)
Definition: BcMathCalculator.php:41
Money\Number\isHalf
isHalf()
Definition: Number.php:120