Passed
Branch feature/scientific-notation-su... (a0527d)
by kacper
01:42
created

BC::convertScientificNotationToString()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

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