Passed
Push — master ( 3d8e1d...a30a03 )
by kacper
01:37
created

BC::convertScientificNotationToString()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 6

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
ccs 11
cts 11
cp 1
rs 8.8571
cc 6
eloc 11
nc 5
nop 1
crap 6
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 9
    public static function setScale($scale)
19
    {
20 9
        bcscale($scale);
21 9
    }
22
23
    /**
24
     * @param int|string $number
25
     * @param int $precision
26
     * @return string
27
     */
28 1
    public static function round($number, $precision = 0)
29
    {
30 1
        $number = (string)self::convertScientificNotationToString($number);
31 1
        if (self::checkIsFloat($number)) {
32 1
            if (self::isNegative($number)) {
33 1
                return self::sub($number, '0.' . str_repeat('0', $precision) . '5', $precision);
34
            }
35
36 1
            return self::add($number, '0.' . str_repeat('0', $precision) . '5', $precision);
37
        }
38
39 1
        return self::checkNumber($number);
40
    }
41
42
    /**
43
     * @param int|string|float $number
44
     * @return string
45
     */
46 21
    public static function convertScientificNotationToString($number)
47
    {
48 21
        if (false !== stripos($number, 'E') && preg_match('/(-?\d\.\d+)E([+|-])(\d+)/i', $number, $regs)) {
49 14
            if ('+' === $regs[2]) {
50 5
                $number = self::mul(self::pow(10, $regs[3]), $regs[1]);
51 14
            } else if ('-' === $regs[2]) {
52 14
                $length = $regs[3];
53 14
                $check = explode('.', $regs[1]);
54 14
                if (!empty($check[1])) {
55 12
                    $length += strlen($check[1]);
56
                }
57 14
                $number = self::div($regs[1], self::pow(10, $regs[3], $regs[3]), $length);
58
            }
59
        }
60 21
        return self::checkNumber($number);
61
    }
62
63
    /**
64
     * @param string $leftOperand
65
     * @param string $rightOperand
66
     * @param int $scale
67
     * @return string
68
     */
69 10 View Code Duplication
    public static function mul($leftOperand, $rightOperand, $scale = null)
70
    {
71 10
        $leftOperand = self::convertScientificNotationToString($leftOperand);
72 10
        $rightOperand = self::convertScientificNotationToString($rightOperand);
73
74 10
        if (null === $scale) {
75 8
            return bcmul($leftOperand, $rightOperand);
76
        }
77 5
        return bcmul($leftOperand, $rightOperand, $scale);
78
    }
79
80
    /**
81
     * @param string $leftOperand
82
     * @param string $rightOperand
83
     * @param int $scale
84
     * @return string
85
     */
86 15 View Code Duplication
    public static function pow($leftOperand, $rightOperand, $scale = null)
87
    {
88 15
        $leftOperand = self::convertScientificNotationToString($leftOperand);
89 15
        $rightOperand = self::convertScientificNotationToString($rightOperand);
90
91 15
        if (null === $scale) {
92 8
            return bcpow($leftOperand, $rightOperand);
93
        }
94 15
        return bcpow($leftOperand, $rightOperand, $scale);
95
    }
96
97
    /**
98
     * @param string $leftOperand
99
     * @param string $rightOperand
100
     * @param int $scale
101
     * @return string
102
     */
103 15 View Code Duplication
    public static function div($leftOperand, $rightOperand, $scale = null)
104
    {
105 15
        $leftOperand = self::convertScientificNotationToString($leftOperand);
106 15
        $rightOperand = self::convertScientificNotationToString($rightOperand);
107
108 15
        if (null === $scale) {
109 3
            return bcdiv($leftOperand, $rightOperand);
110
        }
111 15
        return bcdiv($leftOperand, $rightOperand, $scale);
112
    }
113
114
    /**
115
     * @param int|string $number
116
     * @return int|string
117
     */
118 21
    private static function checkNumber($number)
119
    {
120 21
        $number = str_replace('+', '', filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
121 21
        if ('-0' === $number || !is_numeric($number)) {
122 7
            return '0';
123
        }
124 21
        return $number;
125
    }
126
127
    /**
128
     * @param int|string $number
129
     * @return bool
130
     */
131 6
    private static function checkIsFloat($number)
132
    {
133 6
        return false !== strpos($number, '.');
134
    }
135
136
    /**
137
     * @param $number
138
     * @return bool
139
     */
140 7
    private static function isNegative($number)
141
    {
142 7
        return 0 === strncmp('-', $number, 1);
143
    }
144
145
    /**
146
     * @param string $leftOperand
147
     * @param string $rightOperand
148
     * @param int $scale
149
     * @return string
150
     */
151 4 View Code Duplication
    public static function sub($leftOperand, $rightOperand, $scale = null)
152
    {
153 4
        $leftOperand = self::convertScientificNotationToString($leftOperand);
154 4
        $rightOperand = self::convertScientificNotationToString($rightOperand);
155
156 4
        if (null === $scale) {
157 2
            return bcsub($leftOperand, $rightOperand);
158
        }
159 3
        return bcsub($leftOperand, $rightOperand, $scale);
160
    }
161
162
    /**
163
     * @param string $leftOperand
164
     * @param string $rightOperand
165
     * @param int $scale
166
     * @return string
167
     */
168 8 View Code Duplication
    public static function add($leftOperand, $rightOperand, $scale = null)
169
    {
170 8
        $leftOperand = self::convertScientificNotationToString($leftOperand);
171 8
        $rightOperand = self::convertScientificNotationToString($rightOperand);
172
173 8
        if (null === $scale) {
174 2
            return bcadd($leftOperand, $rightOperand);
175
        }
176 8
        return bcadd($leftOperand, $rightOperand, $scale);
177
    }
178
179
    /**
180
     * @param int|string $number
181
     * @return string
182
     */
183 1
    public static function abs($number)
184
    {
185 1
        $number = (string)self::convertScientificNotationToString($number);
186
187 1
        if (self::isNegative($number)) {
188 1
            $number = (string)substr($number, 1);
189
        }
190
191 1
        return self::checkNumber($number);
192
    }
193
194
    /**
195
     * @param int|string $min
196
     * @param int|string $max
197
     * @return string
198
     */
199 1
    public static function rand($min, $max)
200
    {
201 1
        $max = (string)self::convertScientificNotationToString($max);
202 1
        $min = (string)self::convertScientificNotationToString($min);
203
204 1
        $difference = self::add(self::sub($max, $min), 1);
205 1
        $randPercent = self::div(mt_rand(), mt_getrandmax(), 8);
206
207 1
        return self::add($min, self::mul($difference, $randPercent, 8), 0);
208
    }
209
210
    /**
211
     * @param array|int|string,...
212
     * @return null|string
213
     */
214 1 View Code Duplication
    public static function max()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
215
    {
216 1
        $max = null;
217 1
        $args = func_get_args();
218 1
        if (is_array($args[0])) {
219 1
            $args = $args[0];
220
        }
221 1
        foreach ($args as $number) {
222 1
            $number = self::convertScientificNotationToString($number);
223 1
            if (null === $max) {
224 1
                $max = $number;
225 1
            } else if (self::comp($max, $number) === self::COMPARE_RIGHT_GRATER) {
226 1
                $max = $number;
227
            }
228
        }
229
230 1
        return $max;
231
    }
232
233
    /**
234
     * @param string $leftOperand
235
     * @param string $rightOperand
236
     * @param int $scale
237
     * @return int
238
     */
239 3
    public static function comp($leftOperand, $rightOperand, $scale = null)
240
    {
241 3
        $leftOperand = self::convertScientificNotationToString($leftOperand);
242 3
        $rightOperand = self::convertScientificNotationToString($rightOperand);
243
244 3
        if (null === $scale) {
245 3
            return bccomp($leftOperand, $rightOperand, max(strlen($leftOperand), strlen($rightOperand)));
246
        }
247 1
        return bccomp(
248 1
            $leftOperand,
249 1
            $rightOperand,
250 1
            $scale
251
        );
252
    }
253
254
    /**
255
     * @param array|int|string,...
256
     * @return null|string
257
     */
258 1 View Code Duplication
    public static function min()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
259
    {
260 1
        $min = null;
261 1
        $args = func_get_args();
262 1
        if (is_array($args[0])) {
263 1
            $args = $args[0];
264
        }
265 1
        foreach ($args as $number) {
266 1
            $number = self::convertScientificNotationToString($number);
267 1
            if (null === $min) {
268 1
                $min = $number;
269 1
            } else if (self::comp($min, $number) === self::COMPARE_LEFT_GRATER) {
270 1
                $min = $number;
271
            }
272
        }
273
274 1
        return $min;
275
    }
276
277
    /**
278
     * @param int|string $number
279
     * @param int $precision
280
     * @return string
281
     */
282 1 View Code Duplication
    public static function roundDown($number, $precision = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
283
    {
284 1
        $number = (string)self::convertScientificNotationToString($number);
285 1
        $multiply = self::pow(10, (string)abs($precision));
286 1
        return $precision < 0 ?
287 1
            self::mul(self::floor(self::div($number, $multiply)), $multiply, $precision) :
288 1
            self::div(self::floor(self::mul($number, $multiply)), $multiply, $precision);
289
    }
290
291
    /**
292
     * @param int|string $number
293
     * @return string
294
     */
295 3 View Code Duplication
    public static function floor($number)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
296
    {
297 3
        $number = (string)self::convertScientificNotationToString($number);
298 3
        if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
299 3
            $result = 0;
300 3
            if (self::isNegative($number)) {
301 3
                --$result;
302
            }
303 3
            $number = self::add($number, $result, 0);
304
        }
305
306 3
        return self::checkNumber($number);
307
    }
308
309
    /**
310
     * @param int|string $number
311
     * @return bool
312
     */
313 5
    private static function checkIsFloatCleanZeros(&$number)
314
    {
315 5
        return false !== strpos($number = rtrim(rtrim($number, '0'), '.'), '.');
316
    }
317
318
    /**
319
     * @param int|string $number
320
     * @param int $precision
321
     * @return string
322
     */
323 1 View Code Duplication
    public static function roundUp($number, $precision = 0)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
324
    {
325 1
        $number = (string)self::convertScientificNotationToString($number);
326 1
        $multiply = self::pow(10, (string)abs($precision));
327 1
        return $precision < 0 ?
328 1
            self::mul(self::ceil(self::div($number, $multiply)), $multiply, $precision) :
329 1
            self::div(self::ceil(self::mul($number, $multiply)), $multiply, $precision);
330
    }
331
332
    /**
333
     * @param int|string $number
334
     * @return string
335
     */
336 2 View Code Duplication
    public static function ceil($number)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
337
    {
338 2
        $number = (string)self::convertScientificNotationToString($number);
339 2
        if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
340 2
            $result = 1;
341 2
            if (self::isNegative($number)) {
342 2
                --$result;
343
            }
344 2
            $number = self::add($number, $result, 0);
345
        }
346
347 2
        return self::checkNumber($number);
348
    }
349
350
    /**
351
     * @return int
352
     */
353 1
    public static function getScale()
354
    {
355 1
        $sqrt = self::sqrt('2');
356 1
        return strlen(substr($sqrt, strpos($sqrt, '.') + 1));
357
    }
358
359
    /**
360
     * @param string $operand
361
     * @param int $scale
362
     * @return string
363
     */
364 2
    public static function sqrt($operand, $scale = null)
365
    {
366 2
        $operand = self::convertScientificNotationToString($operand);
367
368 2
        if (null === $scale) {
369 2
            return bcsqrt($operand);
370
        }
371 1
        return bcsqrt($operand, $scale);
372
    }
373
374
    /**
375
     * @param string $leftOperand
376
     * @param string $modulus
377
     * @param int $scale
378
     * @return string
379
     */
380 1
    public static function fmod($leftOperand, $modulus, $scale = null)
381
    {
382 1
        $leftOperand = self::convertScientificNotationToString($leftOperand);
383
384
        // From PHP 7.2 on, bcmod can handle real numbers
385 1
        if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
386
            return self::mod($leftOperand, $modulus);
387
        }
388
389
        // mod(a, b) = a - b * floor(a/b)
390 1
        return self::sub(
391 1
            $leftOperand,
392 1
            self::mul(
393 1
                $modulus,
394 1
                self::floor(self::div($leftOperand, $modulus, $scale)),
395 1
                $scale
396
            ),
397 1
            $scale
398
        );
399
    }
400
401
    /**
402
     * @param string $leftOperand
403
     * @param string $modulus
404
     * @return string
405
     */
406 1
    public static function mod($leftOperand, $modulus)
407
    {
408 1
        return bcmod(
409 1
            self::convertScientificNotationToString($leftOperand),
410 1
            $modulus
411
        );
412
    }
413
414
    /**
415
     * @param string $leftOperand
416
     * @param string $rightOperand
417
     * @param string $modulus
418
     * @param int $scale
419
     * @return string
420
     */
421 1 View Code Duplication
    public static function powMod($leftOperand, $rightOperand, $modulus, $scale = null)
422
    {
423 1
        $leftOperand = self::convertScientificNotationToString($leftOperand);
424 1
        $rightOperand = self::convertScientificNotationToString($rightOperand);
425
426 1
        if (null === $scale) {
427 1
            return bcpowmod($leftOperand, $rightOperand, $modulus);
428
        }
429
        return bcpowmod($leftOperand, $rightOperand, $modulus, $scale);
430
    }
431
}
432