Passed
Pull Request — master (#14)
by kacper
01:41
created

BC::convertScientificNotationToString()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 16
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

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 5
eloc 11
nc 5
nop 1
crap 5
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
     * @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 19
    public static function convertScientificNotationToString($number)
47
    {
48 19
        if (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 19
        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
    public static function pow($leftOperand, $rightOperand, $scale = null)
87
    {
88 15
        $leftOperand = self::convertScientificNotationToString($leftOperand);
89 15
        $rightOperand = self::convertScientificNotationToString($rightOperand);
90
91 15
        return bcpow($leftOperand, $rightOperand, $scale);
92
    }
93
94
    /**
95
     * @param string $leftOperand
96
     * @param string $rightOperand
97
     * @param int $scale
98
     * @return string
99
     */
100 15 View Code Duplication
    public static function div($leftOperand, $rightOperand, $scale = null)
101
    {
102 15
        $leftOperand = self::convertScientificNotationToString($leftOperand);
103 15
        $rightOperand = self::convertScientificNotationToString($rightOperand);
104
105 15
        if (null === $scale) {
106 3
            return bcdiv($leftOperand, $rightOperand);
107
        }
108 15
        return bcdiv($leftOperand, $rightOperand, $scale);
109
    }
110
111
    /**
112
     * @param int|string $number
113
     * @return int|string
114
     */
115 19
    private static function checkNumber($number)
116
    {
117 19
        $number = str_replace('+', '', filter_var($number, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION));
118 19
        if ('-0' === $number || !is_numeric($number)) {
119 7
            return '0';
120
        }
121 19
        return $number;
122
    }
123
124
    /**
125
     * @param int|string $number
126
     * @return bool
127
     */
128 6
    private static function checkIsFloat($number)
129
    {
130 6
        return false !== strpos($number, '.');
131
    }
132
133
    /**
134
     * @param $number
135
     * @return bool
136
     */
137 7
    private static function isNegative($number)
138
    {
139 7
        return 0 === strncmp('-', $number, 1);
140
    }
141
142
    /**
143
     * @param string $leftOperand
144
     * @param string $rightOperand
145
     * @param int $scale
146
     * @return string
147
     */
148 4
    public static function sub($leftOperand, $rightOperand, $scale = null)
149
    {
150 4
        return bcsub(self::convertScientificNotationToString($leftOperand),
151 4
            self::convertScientificNotationToString($rightOperand), $scale);
152
    }
153
154
    /**
155
     * @param string $leftOperand
156
     * @param string $rightOperand
157
     * @param int $scale
158
     * @return string
159
     */
160 8
    public static function add($leftOperand, $rightOperand, $scale = null)
161
    {
162 8
        return bcadd(
163 8
            self::convertScientificNotationToString($leftOperand),
164 8
            self::convertScientificNotationToString($rightOperand),
165 8
            $scale
166
        );
167
    }
168
169
    /**
170
     * @param int|string $number
171
     * @return string
172
     */
173 1
    public static function abs($number)
174
    {
175 1
        $number = (string)self::convertScientificNotationToString($number);
176
177 1
        if (self::isNegative($number)) {
178 1
            $number = (string)substr($number, 1);
179
        }
180
181 1
        return self::checkNumber($number);
182
    }
183
184
    /**
185
     * @param int|string $min
186
     * @param int|string $max
187
     * @return string
188
     */
189 1
    public static function rand($min, $max)
190
    {
191 1
        $max = (string)self::convertScientificNotationToString($max);
192 1
        $min = (string)self::convertScientificNotationToString($min);
193
194 1
        $difference = self::add(self::sub($max, $min), 1);
195 1
        $randPercent = self::div(mt_rand(), mt_getrandmax(), 8);
196
197 1
        return self::add($min, self::mul($difference, $randPercent, 8), 0);
198
    }
199
200
    /**
201
     * @param array|int|string,...
202
     * @return null|string
203
     */
204 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...
205
    {
206 1
        $max = null;
207 1
        $args = func_get_args();
208 1
        if (is_array($args[0])) {
209 1
            $args = $args[0];
210
        }
211 1
        foreach ($args as $number) {
212 1
            $number = self::convertScientificNotationToString($number);
213 1
            if (null === $max) {
214 1
                $max = $number;
215 1
            } else if (self::comp($max, $number) < 0) {
216 1
                $max = $number;
217
            }
218
        }
219
220 1
        return $max;
221
    }
222
223
    /**
224
     * @param string $leftOperand
225
     * @param string $rightOperand
226
     * @param int $scale
227
     * @return int
228
     */
229 3
    public static function comp($leftOperand, $rightOperand, $scale = null)
230
    {
231 3
        return bccomp(
232 3
            self::convertScientificNotationToString($leftOperand),
233 3
            self::convertScientificNotationToString($rightOperand),
234 3
            $scale
235
        );
236
    }
237
238
    /**
239
     * @param array|int|string,...
240
     * @return null|string
241
     */
242 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...
243
    {
244 1
        $min = null;
245 1
        $args = func_get_args();
246 1
        if (is_array($args[0])) {
247 1
            $args = $args[0];
248
        }
249 1
        foreach ($args as $number) {
250 1
            $number = self::convertScientificNotationToString($number);
251 1
            if (null === $min) {
252 1
                $min = $number;
253 1
            } else if (self::comp($min, $number) > 0) {
254 1
                $min = $number;
255
            }
256
        }
257
258 1
        return $min;
259
    }
260
261
    /**
262
     * @param int|string $number
263
     * @param int $precision
264
     * @return string
265
     */
266 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...
267
    {
268 1
        $number = (string)self::convertScientificNotationToString($number);
269 1
        $multiply = self::pow(10, (string)abs($precision));
270 1
        return $precision < 0 ?
271 1
            self::mul(self::floor(self::div($number, $multiply)), $multiply, $precision) :
272 1
            self::div(self::floor(self::mul($number, $multiply)), $multiply, $precision);
273
    }
274
275
    /**
276
     * @param int|string $number
277
     * @return string
278
     */
279 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...
280
    {
281 3
        $number = (string)self::convertScientificNotationToString($number);
282 3
        if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
283 3
            $result = 0;
284 3
            if (self::isNegative($number)) {
285 3
                --$result;
286
            }
287 3
            $number = self::add($number, $result, 0);
288
        }
289
290 3
        return self::checkNumber($number);
291
    }
292
293
    /**
294
     * @param int|string $number
295
     * @return bool
296
     */
297 5
    private static function checkIsFloatCleanZeros(&$number)
298
    {
299 5
        return false !== strpos($number = rtrim(rtrim($number, '0'), '.'), '.');
300
    }
301
302
    /**
303
     * @param int|string $number
304
     * @param int $precision
305
     * @return string
306
     */
307 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...
308
    {
309 1
        $number = (string)self::convertScientificNotationToString($number);
310 1
        $multiply = self::pow(10, (string)abs($precision));
311 1
        return $precision < 0 ?
312 1
            self::mul(self::ceil(self::div($number, $multiply)), $multiply, $precision) :
313 1
            self::div(self::ceil(self::mul($number, $multiply)), $multiply, $precision);
314
    }
315
316
    /**
317
     * @param int|string $number
318
     * @return string
319
     */
320 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...
321
    {
322 2
        $number = (string)self::convertScientificNotationToString($number);
323 2
        if (self::checkIsFloat($number) && self::checkIsFloatCleanZeros($number)) {
324 2
            $result = 1;
325 2
            if (self::isNegative($number)) {
326 2
                --$result;
327
            }
328 2
            $number = self::add($number, $result, 0);
329
        }
330
331 2
        return self::checkNumber($number);
332
    }
333
334
    /**
335
     * @return int
336
     */
337 1
    public static function getScale()
338
    {
339 1
        $sqrt = bcsqrt('2');
340 1
        return strlen(substr($sqrt, strpos($sqrt, '.') + 1));
341
    }
342
343
    /**
344
     * @param string $leftOperand
345
     * @param string $modulus
346
     * @return string
347
     */
348 1
    public static function mod($leftOperand, $modulus)
349
    {
350 1
        return bcmod(
351 1
            self::convertScientificNotationToString($leftOperand),
352 1
            $modulus
353
        );
354
    }
355
356
    /**
357
     * @param string $leftOperand
358
     * @param string $modulus
359
     * @param int $scale
360
     * @return string
361
     */
362 1
    public static function fmod($leftOperand, $modulus, $scale = null)
363
    {
364 1
        $leftOperand = self::convertScientificNotationToString($leftOperand);
365
366
        // From PHP 7.2 on, bcmod can handle real numbers
367 1
        if (version_compare(PHP_VERSION, '7.2.0') >= 0) {
368
            return bcmod($leftOperand, $modulus);
369
        }
370
371
        // mod(a, b) = a - b * floor(a/b)
372 1
        return self::sub(
373 1
            $leftOperand,
374 1
            self::mul(
375 1
                $modulus,
376 1
                self::floor(self::div($leftOperand, $modulus, $scale)),
377 1
                $scale
378
            ),
379 1
            $scale
380
        );
381
    }
382
383
    /**
384
     * @param string $leftOperand
385
     * @param string $rightOperand
386
     * @param string $modulus
387
     * @param int $scale
388
     * @return string
389
     */
390 1
    public static function powMod($leftOperand, $rightOperand, $modulus, $scale = null)
391
    {
392 1
        return bcpowmod(
393 1
            self::convertScientificNotationToString($leftOperand),
394 1
            self::convertScientificNotationToString($rightOperand),
395 1
            $modulus,
396 1
            $scale
397
        );
398
    }
399
400
    /**
401
     * @param string $operand
402
     * @param int $scale
403
     * @return string
404
     */
405 1
    public static function sqrt($operand, $scale = null)
406
    {
407 1
        return bcsqrt($operand, $scale);
408
    }
409
}
410