1
|
|
|
<?php
|
2
|
|
|
|
3
|
|
|
namespace BCMathExtended;
|
4
|
|
|
|
5
|
|
|
/**
|
6
|
|
|
* Class BC
|
7
|
|
|
* @package BCMathExtended
|
8
|
|
|
*/
|
9
|
|
|
class BC
|
10
|
|
|
{
|
11
|
|
|
const COMPARE_EQUAL = 0;
|
12
|
|
|
const COMPARE_LEFT_GRATER = 1;
|
13
|
|
|
const COMPARE_RIGHT_GRATER = -1;
|
14
|
|
|
|
15
|
|
|
/**
|
16
|
|
|
* @param int $scale
|
17
|
|
|
*/
|
18
|
2 |
|
public static function setScale($scale)
|
19
|
|
|
{
|
20
|
2 |
|
bcscale($scale);
|
21
|
2 |
|
}
|
22
|
|
|
|
23
|
|
|
/**
|
24
|
|
|
* @param int|string $number
|
25
|
|
|
* @return string
|
26
|
|
|
*/
|
27
|
2 |
View Code Duplication |
public static function ceil($number)
|
|
|
|
|
28
|
|
|
{
|
29
|
2 |
|
$number = (string)$number;
|
30
|
|
|
|
31
|
2 |
|
if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
|
32
|
2 |
|
$result = 1;
|
33
|
2 |
|
if (self::isNegative($number)) {
|
34
|
2 |
|
--$result;
|
35
|
|
|
}
|
36
|
2 |
|
$number = self::add($number, $result, 0);
|
37
|
|
|
}
|
38
|
|
|
|
39
|
2 |
|
return self::checkNumber($number);
|
40
|
|
|
}
|
41
|
|
|
|
42
|
|
|
/**
|
43
|
|
|
* @param int|string $number
|
44
|
|
|
* @return bool
|
45
|
|
|
*/
|
46
|
6 |
|
private static function checkIsFloat($number)
|
47
|
|
|
{
|
48
|
6 |
|
return false !== strpos($number, '.');
|
49
|
|
|
}
|
50
|
|
|
|
51
|
|
|
/**
|
52
|
|
|
* @param int|string $number
|
53
|
|
|
* @return bool
|
54
|
|
|
*/
|
55
|
5 |
|
private static function checkIsFloatCleanZeros(&$number)
|
56
|
|
|
{
|
57
|
5 |
|
return false !== strpos($number = rtrim(rtrim($number, '0'), '.'), '.');
|
58
|
|
|
}
|
59
|
|
|
|
60
|
|
|
/**
|
61
|
|
|
* @param $number
|
62
|
|
|
* @return bool
|
63
|
|
|
*/
|
64
|
6 |
|
private static function isNegative($number)
|
65
|
|
|
{
|
66
|
6 |
|
return 0 === strncmp('-', $number, 1);
|
67
|
|
|
}
|
68
|
|
|
|
69
|
|
|
/**
|
70
|
|
|
* @param int|string $number
|
71
|
|
|
* @return int|string
|
72
|
|
|
*/
|
73
|
7 |
|
private static function checkNumber($number)
|
74
|
|
|
{
|
75
|
7 |
|
$number = str_replace('+', '', filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
|
76
|
7 |
|
if ('-0' === $number || !is_numeric($number)) {
|
77
|
4 |
|
return '0';
|
78
|
|
|
}
|
79
|
7 |
|
return $number;
|
80
|
|
|
}
|
81
|
|
|
|
82
|
|
|
/**
|
83
|
|
|
* @param int|string $number
|
84
|
|
|
* @param int $precision
|
85
|
|
|
* @return string
|
86
|
|
|
*/
|
87
|
1 |
|
public static function round($number, $precision = 0)
|
88
|
|
|
{
|
89
|
1 |
|
$number = (string)$number;
|
90
|
|
|
|
91
|
1 |
|
if (self::checkIsFloat($number)) {
|
92
|
1 |
|
if (self::isNegative($number)) {
|
93
|
1 |
|
return self::sub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
|
94
|
|
|
}
|
95
|
|
|
|
96
|
1 |
|
return self::add($number, '0.' . str_repeat('0', $precision) . '5', $precision);
|
97
|
|
|
}
|
98
|
|
|
|
99
|
1 |
|
return self::checkNumber($number);
|
100
|
|
|
}
|
101
|
|
|
|
102
|
|
|
/**
|
103
|
|
|
* @param int|string $number
|
104
|
|
|
* @return string
|
105
|
|
|
*/
|
106
|
3 |
View Code Duplication |
public static function floor($number)
|
|
|
|
|
107
|
|
|
{
|
108
|
3 |
|
$number = (string)$number;
|
109
|
|
|
|
110
|
3 |
|
if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
|
111
|
2 |
|
$result = 0;
|
112
|
2 |
|
if (self::isNegative($number)) {
|
113
|
2 |
|
--$result;
|
114
|
|
|
}
|
115
|
2 |
|
$number = self::add($number, $result, 0);
|
116
|
|
|
}
|
117
|
|
|
|
118
|
3 |
|
return self::checkNumber($number);
|
119
|
|
|
}
|
120
|
|
|
|
121
|
|
|
/**
|
122
|
|
|
* @param int|string $number
|
123
|
|
|
* @return string
|
124
|
|
|
*/
|
125
|
1 |
|
public static function abs($number)
|
126
|
|
|
{
|
127
|
1 |
|
$number = (string)$number;
|
128
|
|
|
|
129
|
1 |
|
if (self::isNegative($number)) {
|
130
|
1 |
|
$number = (string)substr($number, 1);
|
131
|
|
|
}
|
132
|
|
|
|
133
|
1 |
|
return self::checkNumber($number);
|
134
|
|
|
}
|
135
|
|
|
|
136
|
|
|
/**
|
137
|
|
|
* @param int|string $min
|
138
|
|
|
* @param int|string $max
|
139
|
|
|
* @return string
|
140
|
|
|
*/
|
141
|
1 |
|
public static function rand($min, $max)
|
142
|
|
|
{
|
143
|
1 |
|
$max = (string)$max;
|
144
|
1 |
|
$min = (string)$min;
|
145
|
|
|
|
146
|
1 |
|
$difference = self::add(self::sub($max, $min), 1);
|
147
|
1 |
|
$randPercent = self::div(mt_rand(), mt_getrandmax(), 8);
|
148
|
|
|
|
149
|
1 |
|
return self::add($min, self::mul($difference, $randPercent, 8), 0);
|
150
|
|
|
}
|
151
|
|
|
|
152
|
|
|
/**
|
153
|
|
|
* @param array|int|string,...
|
154
|
|
|
* @return null|int|string
|
155
|
|
|
*/
|
156
|
1 |
View Code Duplication |
public static function max()
|
|
|
|
|
157
|
|
|
{
|
158
|
1 |
|
$max = null;
|
159
|
1 |
|
$args = func_get_args();
|
160
|
1 |
|
if (is_array($args[0])) {
|
161
|
1 |
|
$args = $args[0];
|
162
|
|
|
}
|
163
|
1 |
|
foreach ($args as $value) {
|
164
|
1 |
|
if (null === $max) {
|
165
|
1 |
|
$max = $value;
|
166
|
|
|
} else {
|
167
|
1 |
|
if (self::comp($max, $value) < 0) {
|
168
|
1 |
|
$max = $value;
|
169
|
|
|
}
|
170
|
|
|
}
|
171
|
|
|
}
|
172
|
|
|
|
173
|
1 |
|
return $max;
|
174
|
|
|
}
|
175
|
|
|
|
176
|
|
|
/**
|
177
|
|
|
* @param array|int|string,...
|
178
|
|
|
* @return null|int|string
|
179
|
|
|
*/
|
180
|
1 |
View Code Duplication |
public static function min()
|
|
|
|
|
181
|
|
|
{
|
182
|
1 |
|
$min = null;
|
183
|
1 |
|
$args = func_get_args();
|
184
|
1 |
|
if (is_array($args[0])) {
|
185
|
1 |
|
$args = $args[0];
|
186
|
|
|
}
|
187
|
1 |
|
foreach ($args as $value) {
|
188
|
1 |
|
if (null === $min) {
|
189
|
1 |
|
$min = $value;
|
190
|
|
|
} else {
|
191
|
1 |
|
if (self::comp($min, $value) > 0) {
|
192
|
1 |
|
$min = $value;
|
193
|
|
|
}
|
194
|
|
|
}
|
195
|
|
|
}
|
196
|
|
|
|
197
|
1 |
|
return $min;
|
198
|
|
|
}
|
199
|
|
|
|
200
|
|
|
/**
|
201
|
|
|
* @param int|string $number
|
202
|
|
|
* @param int $precision
|
203
|
|
|
* @return string
|
204
|
|
|
*/
|
205
|
1 |
View Code Duplication |
public static function roundDown($number, $precision = 0)
|
|
|
|
|
206
|
|
|
{
|
207
|
1 |
|
$multiply = self::pow(10, (string)abs($precision));
|
208
|
1 |
|
return $precision < 0 ?
|
209
|
1 |
|
self::mul(self::floor(self::div($number, $multiply)), $multiply, $precision) :
|
210
|
1 |
|
self::div(self::floor(self::mul($number, $multiply)), $multiply, $precision);
|
211
|
|
|
}
|
212
|
|
|
|
213
|
|
|
/**
|
214
|
|
|
* @param int|string $number
|
215
|
|
|
* @param int $precision
|
216
|
|
|
* @return string
|
217
|
|
|
*/
|
218
|
1 |
View Code Duplication |
public static function roundUp($number, $precision = 0)
|
|
|
|
|
219
|
|
|
{
|
220
|
1 |
|
$multiply = self::pow(10, (string)abs($precision));
|
221
|
1 |
|
return $precision < 0 ?
|
222
|
1 |
|
self::mul(self::ceil(self::div($number, $multiply)), $multiply, $precision) :
|
223
|
1 |
|
self::div(self::ceil(self::mul($number, $multiply)), $multiply, $precision);
|
224
|
|
|
}
|
225
|
|
|
|
226
|
|
|
/**
|
227
|
|
|
* @return int
|
228
|
|
|
*/
|
229
|
1 |
|
public static function getScale()
|
230
|
|
|
{
|
231
|
1 |
|
$sqrt = bcsqrt('2');
|
232
|
1 |
|
return strlen(substr($sqrt, strpos($sqrt, '.') + 1));
|
233
|
|
|
}
|
234
|
|
|
|
235
|
|
|
/**
|
236
|
|
|
* @param string $leftOperand
|
237
|
|
|
* @param string $rightOperand
|
238
|
|
|
* @param int $scale
|
239
|
|
|
* @return string
|
240
|
|
|
*/
|
241
|
7 |
|
public static function add($leftOperand, $rightOperand, $scale = null)
|
242
|
|
|
{
|
243
|
7 |
|
return bcadd($leftOperand, $rightOperand, $scale);
|
244
|
|
|
}
|
245
|
|
|
|
246
|
|
|
/**
|
247
|
|
|
* @param string $leftOperand
|
248
|
|
|
* @param string $rightOperand
|
249
|
|
|
* @param int $scale
|
250
|
|
|
* @return int
|
251
|
|
|
*/
|
252
|
3 |
|
public static function comp($leftOperand, $rightOperand, $scale = null)
|
253
|
|
|
{
|
254
|
3 |
|
return bccomp($leftOperand, $rightOperand, $scale);
|
255
|
|
|
}
|
256
|
|
|
|
257
|
|
|
/**
|
258
|
|
|
* @param string $leftOperand
|
259
|
|
|
* @param string $rightOperand
|
260
|
|
|
* @param int $scale
|
261
|
|
|
* @return string
|
262
|
|
|
*/
|
263
|
5 |
|
public static function div($leftOperand, $rightOperand, $scale = null)
|
264
|
|
|
{
|
265
|
5 |
|
if (null === $scale) {
|
266
|
3 |
|
return bcdiv($leftOperand, $rightOperand);
|
267
|
|
|
}
|
268
|
5 |
|
return bcdiv($leftOperand, $rightOperand, $scale);
|
269
|
|
|
}
|
270
|
|
|
|
271
|
|
|
/**
|
272
|
|
|
* @param string $leftOperand
|
273
|
|
|
* @param string $modulus
|
274
|
|
|
* @return string
|
275
|
|
|
*/
|
276
|
1 |
|
public static function mod($leftOperand, $modulus)
|
277
|
|
|
{
|
278
|
1 |
|
return bcmod($leftOperand, $modulus);
|
279
|
|
|
}
|
280
|
|
|
|
281
|
|
|
/**
|
282
|
|
|
* @param string $leftOperand
|
283
|
|
|
* @param string $modulus
|
284
|
|
|
* @param int $scale
|
285
|
|
|
* @return string
|
286
|
|
|
*/
|
287
|
1 |
|
public static function fmod($leftOperand, $modulus, $scale = null)
|
288
|
|
|
{
|
289
|
|
|
// From PHP 7.2 on, bcmod can handle real numbers
|
290
|
1 |
|
if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
|
291
|
|
|
return bcmod($leftOperand, $modulus);
|
292
|
|
|
}
|
293
|
|
|
|
294
|
|
|
// mod(a, b) = a - b * floor(a/b)
|
295
|
1 |
|
return self::sub(
|
296
|
1 |
|
$leftOperand,
|
297
|
1 |
|
self::mul(
|
298
|
1 |
|
$modulus,
|
299
|
1 |
|
self::floor(self::div($leftOperand, $modulus, $scale)),
|
300
|
1 |
|
$scale
|
301
|
|
|
),
|
302
|
1 |
|
$scale
|
303
|
|
|
);
|
304
|
|
|
}
|
305
|
|
|
|
306
|
|
|
/**
|
307
|
|
|
* @param string $leftOperand
|
308
|
|
|
* @param string $rightOperand
|
309
|
|
|
* @param int $scale
|
310
|
|
|
* @return string
|
311
|
|
|
*/
|
312
|
5 |
|
public static function mul($leftOperand, $rightOperand, $scale = null)
|
313
|
|
|
{
|
314
|
5 |
|
if (null === $scale) {
|
315
|
3 |
|
return bcmul($leftOperand, $rightOperand);
|
316
|
|
|
}
|
317
|
5 |
|
return bcmul($leftOperand, $rightOperand, $scale);
|
318
|
|
|
}
|
319
|
|
|
|
320
|
|
|
/**
|
321
|
|
|
* @param string $leftOperand
|
322
|
|
|
* @param string $rightOperand
|
323
|
|
|
* @param int $scale
|
324
|
|
|
* @return string
|
325
|
|
|
*/
|
326
|
3 |
|
public static function pow($leftOperand, $rightOperand, $scale = null)
|
327
|
|
|
{
|
328
|
3 |
|
return bcpow($leftOperand, $rightOperand, $scale);
|
329
|
|
|
}
|
330
|
|
|
|
331
|
|
|
/**
|
332
|
|
|
* @param string $leftOperand
|
333
|
|
|
* @param string $rightOperand
|
334
|
|
|
* @param string $modulus
|
335
|
|
|
* @param int $scale
|
336
|
|
|
* @return string
|
337
|
|
|
*/
|
338
|
1 |
|
public static function powMod($leftOperand, $rightOperand, $modulus, $scale = null)
|
339
|
|
|
{
|
340
|
1 |
|
return bcpowmod($leftOperand, $rightOperand, $modulus, $scale);
|
341
|
|
|
}
|
342
|
|
|
|
343
|
|
|
/**
|
344
|
|
|
* @param string $operand
|
345
|
|
|
* @param int $scale
|
346
|
|
|
* @return string
|
347
|
|
|
*/
|
348
|
1 |
|
public static function sqrt($operand, $scale = null)
|
349
|
|
|
{
|
350
|
1 |
|
return bcsqrt($operand, $scale);
|
351
|
|
|
}
|
352
|
|
|
|
353
|
|
|
/**
|
354
|
|
|
* @param string $leftOperand
|
355
|
|
|
* @param string $rightOperand
|
356
|
|
|
* @param int $scale
|
357
|
|
|
* @return string
|
358
|
|
|
*/
|
359
|
4 |
|
public static function sub($leftOperand, $rightOperand, $scale = null)
|
360
|
|
|
{
|
361
|
4 |
|
return bcsub($leftOperand, $rightOperand, $scale);
|
362
|
|
|
}
|
363
|
|
|
}
|
364
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.