Passed
Push — master ( a97294...8972d3 )
by Adrien
28:45 queued 21:13
created

MathTrig::SUBTOTAL()   C

Complexity

Conditions 15
Paths 25

Size

Total Lines 41
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 32
CRAP Score 15.0062

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 15
eloc 32
c 2
b 0
f 1
nc 25
nop 1
dl 0
loc 41
ccs 32
cts 33
cp 0.9697
crap 15.0062
rs 5.9166

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation;
4
5
use Matrix\Exception as MatrixException;
6
use Matrix\Matrix;
7
8
class MathTrig
9
{
10
    //
11
    //    Private method to return an array of the factors of the input value
12
    //
13 12
    private static function factors($value)
14
    {
15 12
        $startVal = floor(sqrt($value));
16
17 12
        $factorArray = [];
18 12
        for ($i = $startVal; $i > 1; --$i) {
19 11
            if (($value % $i) == 0) {
20 8
                $factorArray = array_merge($factorArray, self::factors($value / $i));
21 8
                $factorArray = array_merge($factorArray, self::factors($i));
22 8
                if ($i <= sqrt($value)) {
23 8
                    break;
24
                }
25
            }
26
        }
27 12
        if (!empty($factorArray)) {
28 8
            rsort($factorArray);
29
30 8
            return $factorArray;
31
        }
32
33 12
        return [(int) $value];
34
    }
35
36 6
    private static function romanCut($num, $n)
37
    {
38 6
        return ($num - ($num % $n)) / $n;
39
    }
40
41
    /**
42
     * ATAN2.
43
     *
44
     * This function calculates the arc tangent of the two variables x and y. It is similar to
45
     *        calculating the arc tangent of y ÷ x, except that the signs of both arguments are used
46
     *        to determine the quadrant of the result.
47
     * The arctangent is the angle from the x-axis to a line containing the origin (0, 0) and a
48
     *        point with coordinates (xCoordinate, yCoordinate). The angle is given in radians between
49
     *        -pi and pi, excluding -pi.
50
     *
51
     * Note that the Excel ATAN2() function accepts its arguments in the reverse order to the standard
52
     *        PHP atan2() function, so we need to reverse them here before calling the PHP atan() function.
53
     *
54
     * Excel Function:
55
     *        ATAN2(xCoordinate,yCoordinate)
56
     *
57
     * @category Mathematical and Trigonometric Functions
58
     *
59
     * @param float $xCoordinate the x-coordinate of the point
60
     * @param float $yCoordinate the y-coordinate of the point
61
     *
62
     * @return float the inverse tangent of the specified x- and y-coordinates
63
     */
64 16
    public static function ATAN2($xCoordinate = null, $yCoordinate = null)
65
    {
66 16
        $xCoordinate = Functions::flattenSingleValue($xCoordinate);
67 16
        $yCoordinate = Functions::flattenSingleValue($yCoordinate);
68
69 16
        $xCoordinate = ($xCoordinate !== null) ? $xCoordinate : 0.0;
70 16
        $yCoordinate = ($yCoordinate !== null) ? $yCoordinate : 0.0;
71
72 16
        if (((is_numeric($xCoordinate)) || (is_bool($xCoordinate))) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (is_numeric($xCoordinate...| is_bool($yCoordinate), Probably Intended Meaning: is_numeric($xCoordinate)... is_bool($yCoordinate))
Loading history...
73 16
            ((is_numeric($yCoordinate))) || (is_bool($yCoordinate))) {
74 15
            $xCoordinate = (float) $xCoordinate;
75 15
            $yCoordinate = (float) $yCoordinate;
76
77 15
            if (($xCoordinate == 0) && ($yCoordinate == 0)) {
78 1
                return Functions::DIV0();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...ation\Functions::DIV0() returns the type string which is incompatible with the documented return type double.
Loading history...
79
            }
80
81 14
            return atan2($yCoordinate, $xCoordinate);
82
        }
83
84 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
85
    }
86
87
    /**
88
     * CEILING.
89
     *
90
     * Returns number rounded up, away from zero, to the nearest multiple of significance.
91
     *        For example, if you want to avoid using pennies in your prices and your product is
92
     *        priced at $4.42, use the formula =CEILING(4.42,0.05) to round prices up to the
93
     *        nearest nickel.
94
     *
95
     * Excel Function:
96
     *        CEILING(number[,significance])
97
     *
98
     * @category Mathematical and Trigonometric Functions
99
     *
100
     * @param float $number the number you want to round
101
     * @param float $significance the multiple to which you want to round
102
     *
103
     * @return float Rounded Number
104
     */
105 43
    public static function CEILING($number, $significance = null)
106
    {
107 43
        $number = Functions::flattenSingleValue($number);
108 43
        $significance = Functions::flattenSingleValue($significance);
109
110 43
        if (($significance === null) &&
111 43
            (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC)) {
112
            $significance = $number / abs($number);
113
        }
114
115 43
        if ((is_numeric($number)) && (is_numeric($significance))) {
116 41
            if (($number == 0.0) || ($significance == 0.0)) {
117 3
                return 0.0;
118 38
            } elseif (self::SIGN($number) == self::SIGN($significance)) {
119 35
                return ceil($number / $significance) * $significance;
120
            }
121
122 3
            return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
123
        }
124
125 2
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
126
    }
127
128
    /**
129
     * COMBIN.
130
     *
131
     * Returns the number of combinations for a given number of items. Use COMBIN to
132
     *        determine the total possible number of groups for a given number of items.
133
     *
134
     * Excel Function:
135
     *        COMBIN(numObjs,numInSet)
136
     *
137
     * @category Mathematical and Trigonometric Functions
138
     *
139
     * @param int $numObjs Number of different objects
140
     * @param int $numInSet Number of objects in each combination
141
     *
142
     * @return int Number of combinations
143
     */
144 35
    public static function COMBIN($numObjs, $numInSet)
145
    {
146 35
        $numObjs = Functions::flattenSingleValue($numObjs);
147 35
        $numInSet = Functions::flattenSingleValue($numInSet);
148
149 35
        if ((is_numeric($numObjs)) && (is_numeric($numInSet))) {
150 34
            if ($numObjs < $numInSet) {
151 3
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
152 31
            } elseif ($numInSet < 0) {
153 2
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
154
            }
155
156 29
            return round(self::FACT($numObjs) / self::FACT($numObjs - $numInSet)) / self::FACT($numInSet);
157
        }
158
159 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
160
    }
161
162
    /**
163
     * EVEN.
164
     *
165
     * Returns number rounded up to the nearest even integer.
166
     * You can use this function for processing items that come in twos. For example,
167
     *        a packing crate accepts rows of one or two items. The crate is full when
168
     *        the number of items, rounded up to the nearest two, matches the crate's
169
     *        capacity.
170
     *
171
     * Excel Function:
172
     *        EVEN(number)
173
     *
174
     * @category Mathematical and Trigonometric Functions
175
     *
176
     * @param float $number Number to round
177
     *
178
     * @return int Rounded Number
179
     */
180 25
    public static function EVEN($number)
181
    {
182 25
        $number = Functions::flattenSingleValue($number);
183
184 25
        if ($number === null) {
185 1
            return 0;
186 24
        } elseif (is_bool($number)) {
187 2
            $number = (int) $number;
188
        }
189
190 24
        if (is_numeric($number)) {
191 23
            $significance = 2 * self::SIGN($number);
192
193 23
            return (int) self::CEILING($number, $significance);
194
        }
195
196 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
197
    }
198
199
    /**
200
     * FACT.
201
     *
202
     * Returns the factorial of a number.
203
     * The factorial of a number is equal to 1*2*3*...* number.
204
     *
205
     * Excel Function:
206
     *        FACT(factVal)
207
     *
208
     * @category Mathematical and Trigonometric Functions
209
     *
210
     * @param float $factVal Factorial Value
211
     *
212
     * @return int Factorial
213
     */
214 167
    public static function FACT($factVal)
215
    {
216 167
        $factVal = Functions::flattenSingleValue($factVal);
217
218 167
        if (is_numeric($factVal)) {
219 166
            if ($factVal < 0) {
220 1
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
221
            }
222 165
            $factLoop = floor($factVal);
223 165
            if ((Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) &&
224 165
                ($factVal > $factLoop)) {
225
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
226
            }
227
228 165
            $factorial = 1;
229 165
            while ($factLoop > 1) {
230 93
                $factorial *= $factLoop--;
231
            }
232
233 165
            return $factorial;
234
        }
235
236 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
237
    }
238
239
    /**
240
     * FACTDOUBLE.
241
     *
242
     * Returns the double factorial of a number.
243
     *
244
     * Excel Function:
245
     *        FACTDOUBLE(factVal)
246
     *
247
     * @category Mathematical and Trigonometric Functions
248
     *
249
     * @param float $factVal Factorial Value
250
     *
251
     * @return int Double Factorial
252
     */
253 8
    public static function FACTDOUBLE($factVal)
254
    {
255 8
        $factLoop = Functions::flattenSingleValue($factVal);
256
257 8
        if (is_numeric($factLoop)) {
258 7
            $factLoop = floor($factLoop);
259 7
            if ($factVal < 0) {
260 1
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
261
            }
262 6
            $factorial = 1;
263 6
            while ($factLoop > 1) {
264 5
                $factorial *= $factLoop--;
265 5
                --$factLoop;
266
            }
267
268 6
            return $factorial;
269
        }
270
271 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
272
    }
273
274
    /**
275
     * FLOOR.
276
     *
277
     * Rounds number down, toward zero, to the nearest multiple of significance.
278
     *
279
     * Excel Function:
280
     *        FLOOR(number[,significance])
281
     *
282
     * @category Mathematical and Trigonometric Functions
283
     *
284
     * @param float $number Number to round
285
     * @param float $significance Significance
286
     *
287
     * @return float Rounded Number
288
     */
289 11
    public static function FLOOR($number, $significance = null)
290
    {
291 11
        $number = Functions::flattenSingleValue($number);
292 11
        $significance = Functions::flattenSingleValue($significance);
293
294 11
        if (($significance === null) &&
295 11
            (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC)) {
296
            $significance = $number / abs($number);
297
        }
298
299 11
        if ((is_numeric($number)) && (is_numeric($significance))) {
300 9
            if ($significance == 0.0) {
301 1
                return Functions::DIV0();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...ation\Functions::DIV0() returns the type string which is incompatible with the documented return type double.
Loading history...
302 8
            } elseif ($number == 0.0) {
303
                return 0.0;
304 8
            } elseif (self::SIGN($number) == self::SIGN($significance)) {
305 6
                return floor($number / $significance) * $significance;
306
            }
307
308 2
            return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
309
        }
310
311 2
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
312
    }
313
314 25
    private static function evaluateGCD($a, $b)
315
    {
316 25
        return $b ? self::evaluateGCD($b, $a % $b) : $a;
317
    }
318
319
    /**
320
     * GCD.
321
     *
322
     * Returns the greatest common divisor of a series of numbers.
323
     * The greatest common divisor is the largest integer that divides both
324
     *        number1 and number2 without a remainder.
325
     *
326
     * Excel Function:
327
     *        GCD(number1[,number2[, ...]])
328
     *
329
     * @category Mathematical and Trigonometric Functions
330
     *
331
     * @param mixed ...$args Data values
332
     *
333
     * @return int Greatest Common Divisor
334
     */
335 27
    public static function GCD(...$args)
336
    {
337 27
        $args = Functions::flattenArray($args);
338
        // Loop through arguments
339 27
        foreach (Functions::flattenArray($args) as $value) {
340 27
            if (!is_numeric($value)) {
341 1
                return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
342 27
            } elseif ($value < 0) {
343 1
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
344
            }
345
        }
346
347 25
        $gcd = (int) array_pop($args);
348
        do {
349 25
            $gcd = self::evaluateGCD($gcd, (int) array_pop($args));
350 25
        } while (!empty($args));
351
352 25
        return $gcd;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $gcd also could return the type mixed which is incompatible with the documented return type integer.
Loading history...
353
    }
354
355
    /**
356
     * INT.
357
     *
358
     * Casts a floating point value to an integer
359
     *
360
     * Excel Function:
361
     *        INT(number)
362
     *
363
     * @category Mathematical and Trigonometric Functions
364
     *
365
     * @param float $number Number to cast to an integer
366
     *
367
     * @return int Integer value
368
     */
369 19
    public static function INT($number)
370
    {
371 19
        $number = Functions::flattenSingleValue($number);
372
373 19
        if ($number === null) {
374 1
            return 0;
375 18
        } elseif (is_bool($number)) {
376 2
            return (int) $number;
377
        }
378 16
        if (is_numeric($number)) {
379 15
            return (int) floor($number);
380
        }
381
382 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
383
    }
384
385
    /**
386
     * LCM.
387
     *
388
     * Returns the lowest common multiplier of a series of numbers
389
     * The least common multiple is the smallest positive integer that is a multiple
390
     * of all integer arguments number1, number2, and so on. Use LCM to add fractions
391
     * with different denominators.
392
     *
393
     * Excel Function:
394
     *        LCM(number1[,number2[, ...]])
395
     *
396
     * @category Mathematical and Trigonometric Functions
397
     *
398
     * @param mixed ...$args Data values
399
     *
400
     * @return int Lowest Common Multiplier
401
     */
402 12
    public static function LCM(...$args)
403
    {
404 12
        $returnValue = 1;
405 12
        $allPoweredFactors = [];
406
        // Loop through arguments
407 12
        foreach (Functions::flattenArray($args) as $value) {
408 12
            if (!is_numeric($value)) {
409 1
                return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
410
            }
411 12
            if ($value == 0) {
412 1
                return 0;
413 12
            } elseif ($value < 0) {
414 1
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type integer.
Loading history...
415
            }
416 12
            $myFactors = self::factors(floor($value));
417 12
            $myCountedFactors = array_count_values($myFactors);
418 12
            $myPoweredFactors = [];
419 12
            foreach ($myCountedFactors as $myCountedFactor => $myCountedPower) {
420 12
                $myPoweredFactors[$myCountedFactor] = pow($myCountedFactor, $myCountedPower);
421
            }
422 12
            foreach ($myPoweredFactors as $myPoweredValue => $myPoweredFactor) {
423 12
                if (isset($allPoweredFactors[$myPoweredValue])) {
424 6
                    if ($allPoweredFactors[$myPoweredValue] < $myPoweredFactor) {
425 6
                        $allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
426
                    }
427
                } else {
428 12
                    $allPoweredFactors[$myPoweredValue] = $myPoweredFactor;
429
                }
430
            }
431
        }
432 9
        foreach ($allPoweredFactors as $allPoweredFactor) {
433 9
            $returnValue *= (int) $allPoweredFactor;
434
        }
435
436 9
        return $returnValue;
437
    }
438
439
    /**
440
     * LOG_BASE.
441
     *
442
     * Returns the logarithm of a number to a specified base. The default base is 10.
443
     *
444
     * Excel Function:
445
     *        LOG(number[,base])
446
     *
447
     * @category Mathematical and Trigonometric Functions
448
     *
449
     * @param float $number The positive real number for which you want the logarithm
450
     * @param float $base The base of the logarithm. If base is omitted, it is assumed to be 10.
451
     *
452
     * @return float
453
     */
454 69
    public static function logBase($number = null, $base = 10)
455
    {
456 69
        $number = Functions::flattenSingleValue($number);
457 69
        $base = ($base === null) ? 10 : (float) Functions::flattenSingleValue($base);
0 ignored issues
show
introduced by
The condition $base === null is always false.
Loading history...
458
459 69
        if ((!is_numeric($base)) || (!is_numeric($number))) {
0 ignored issues
show
introduced by
The condition is_numeric($base) is always true.
Loading history...
460 2
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
461
        }
462 67
        if (($base <= 0) || ($number <= 0)) {
463 18
            return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
464
        }
465
466 49
        return log($number, $base);
467
    }
468
469
    /**
470
     * MDETERM.
471
     *
472
     * Returns the matrix determinant of an array.
473
     *
474
     * Excel Function:
475
     *        MDETERM(array)
476
     *
477
     * @category Mathematical and Trigonometric Functions
478
     *
479
     * @param array $matrixValues A matrix of values
480
     *
481
     * @return float
482
     */
483 14
    public static function MDETERM($matrixValues)
484
    {
485 14
        $matrixData = [];
486 14
        if (!is_array($matrixValues)) {
0 ignored issues
show
introduced by
The condition is_array($matrixValues) is always true.
Loading history...
487
            $matrixValues = [[$matrixValues]];
488
        }
489
490 14
        $row = $maxColumn = 0;
491 14
        foreach ($matrixValues as $matrixRow) {
492 14
            if (!is_array($matrixRow)) {
493
                $matrixRow = [$matrixRow];
494
            }
495 14
            $column = 0;
496 14
            foreach ($matrixRow as $matrixCell) {
497 14
                if ((is_string($matrixCell)) || ($matrixCell === null)) {
498 1
                    return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
499
                }
500 14
                $matrixData[$row][$column] = $matrixCell;
501 14
                ++$column;
502
            }
503 14
            if ($column > $maxColumn) {
504 14
                $maxColumn = $column;
505
            }
506 14
            ++$row;
507
        }
508
509 13
        $matrix = new Matrix($matrixData);
510 13
        if (!$matrix->isSquare()) {
511 1
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
512
        }
513
514
        try {
515 12
            return $matrix->determinant();
516
        } catch (MatrixException $ex) {
517
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
518
        }
519
    }
520
521
    /**
522
     * MINVERSE.
523
     *
524
     * Returns the inverse matrix for the matrix stored in an array.
525
     *
526
     * Excel Function:
527
     *        MINVERSE(array)
528
     *
529
     * @category Mathematical and Trigonometric Functions
530
     *
531
     * @param array $matrixValues A matrix of values
532
     *
533
     * @return array
534
     */
535 10
    public static function MINVERSE($matrixValues)
536
    {
537 10
        $matrixData = [];
538 10
        if (!is_array($matrixValues)) {
0 ignored issues
show
introduced by
The condition is_array($matrixValues) is always true.
Loading history...
539
            $matrixValues = [[$matrixValues]];
540
        }
541
542 10
        $row = $maxColumn = 0;
543 10
        foreach ($matrixValues as $matrixRow) {
544 10
            if (!is_array($matrixRow)) {
545
                $matrixRow = [$matrixRow];
546
            }
547 10
            $column = 0;
548 10
            foreach ($matrixRow as $matrixCell) {
549 10
                if ((is_string($matrixCell)) || ($matrixCell === null)) {
550
                    return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
551
                }
552 10
                $matrixData[$row][$column] = $matrixCell;
553 10
                ++$column;
554
            }
555 10
            if ($column > $maxColumn) {
556 10
                $maxColumn = $column;
557
            }
558 10
            ++$row;
559
        }
560
561 10
        $matrix = new Matrix($matrixData);
562 10
        if (!$matrix->isSquare()) {
563
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
564
        }
565
566 10
        if ($matrix->determinant() == 0.0) {
567
            return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type array.
Loading history...
568
        }
569
570
        try {
571 10
            return $matrix->inverse()->toArray();
572
        } catch (MatrixException $ex) {
573
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
574
        }
575
    }
576
577
    /**
578
     * MMULT.
579
     *
580
     * @param array $matrixData1 A matrix of values
581
     * @param array $matrixData2 A matrix of values
582
     *
583
     * @return array
584
     */
585 8
    public static function MMULT($matrixData1, $matrixData2)
586
    {
587 8
        $matrixAData = $matrixBData = [];
588 8
        if (!is_array($matrixData1)) {
0 ignored issues
show
introduced by
The condition is_array($matrixData1) is always true.
Loading history...
589
            $matrixData1 = [[$matrixData1]];
590
        }
591 8
        if (!is_array($matrixData2)) {
0 ignored issues
show
introduced by
The condition is_array($matrixData2) is always true.
Loading history...
592
            $matrixData2 = [[$matrixData2]];
593
        }
594
595
        try {
596 8
            $rowA = 0;
597 8
            foreach ($matrixData1 as $matrixRow) {
598 8
                if (!is_array($matrixRow)) {
599
                    $matrixRow = [$matrixRow];
600
                }
601 8
                $columnA = 0;
602 8
                foreach ($matrixRow as $matrixCell) {
603 8
                    if ((!is_numeric($matrixCell)) || ($matrixCell === null)) {
604
                        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
605
                    }
606 8
                    $matrixAData[$rowA][$columnA] = $matrixCell;
607 8
                    ++$columnA;
608
                }
609 8
                ++$rowA;
610
            }
611 8
            $matrixA = new Matrix($matrixAData);
612 8
            $rowB = 0;
613 8
            foreach ($matrixData2 as $matrixRow) {
614 8
                if (!is_array($matrixRow)) {
615 1
                    $matrixRow = [$matrixRow];
616
                }
617 8
                $columnB = 0;
618 8
                foreach ($matrixRow as $matrixCell) {
619 8
                    if ((!is_numeric($matrixCell)) || ($matrixCell === null)) {
620
                        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
621
                    }
622 8
                    $matrixBData[$rowB][$columnB] = $matrixCell;
623 8
                    ++$columnB;
624
                }
625 8
                ++$rowB;
626
            }
627 8
            $matrixB = new Matrix($matrixBData);
628
629 8
            if ($columnA != $rowB) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $columnA seems to be defined by a foreach iteration on line 597. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
630 2
                return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
631
            }
632
633 6
            return $matrixA->multiply($matrixB)->toArray();
634
        } catch (MatrixException $ex) {
635
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type array.
Loading history...
636
        }
637
    }
638
639
    /**
640
     * MOD.
641
     *
642
     * @param int $a Dividend
643
     * @param int $b Divisor
644
     *
645
     * @return int Remainder
646
     */
647 10
    public static function MOD($a = 1, $b = 1)
648
    {
649 10
        $a = (float) Functions::flattenSingleValue($a);
650 10
        $b = (float) Functions::flattenSingleValue($b);
651
652 10
        if ($b == 0.0) {
653 1
            return Functions::DIV0();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...ation\Functions::DIV0() returns the type string which is incompatible with the documented return type integer.
Loading history...
654 9
        } elseif (($a < 0.0) && ($b > 0.0)) {
655 1
            return $b - fmod(abs($a), $b);
656 8
        } elseif (($a > 0.0) && ($b < 0.0)) {
657 2
            return $b + fmod($a, abs($b));
658
        }
659
660 6
        return fmod($a, $b);
661
    }
662
663
    /**
664
     * MROUND.
665
     *
666
     * Rounds a number to the nearest multiple of a specified value
667
     *
668
     * @param float $number Number to round
669
     * @param int $multiple Multiple to which you want to round $number
670
     *
671
     * @return float Rounded Number
672
     */
673 13
    public static function MROUND($number, $multiple)
674
    {
675 13
        $number = Functions::flattenSingleValue($number);
676 13
        $multiple = Functions::flattenSingleValue($multiple);
677
678 13
        if ((is_numeric($number)) && (is_numeric($multiple))) {
679 11
            if ($multiple == 0) {
680 1
                return 0;
681
            }
682 10
            if ((self::SIGN($number)) == (self::SIGN($multiple))) {
683 9
                $multiplier = 1 / $multiple;
684
685 9
                return round($number * $multiplier) / $multiplier;
686
            }
687
688 1
            return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
689
        }
690
691 2
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
692
    }
693
694
    /**
695
     * MULTINOMIAL.
696
     *
697
     * Returns the ratio of the factorial of a sum of values to the product of factorials.
698
     *
699
     * @param array of mixed Data Series
0 ignored issues
show
Bug introduced by
The type PhpOffice\PhpSpreadsheet\Calculation\of was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
700
     *
701
     * @return float
702
     */
703 2
    public static function MULTINOMIAL(...$args)
704
    {
705 2
        $summer = 0;
706 2
        $divisor = 1;
707
        // Loop through arguments
708 2
        foreach (Functions::flattenArray($args) as $arg) {
709
            // Is it a numeric value?
710 2
            if (is_numeric($arg)) {
711 2
                if ($arg < 1) {
712
                    return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
713
                }
714 2
                $summer += floor($arg);
715 2
                $divisor *= self::FACT($arg);
716
            } else {
717
                return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
718
            }
719
        }
720
721
        // Return
722 2
        if ($summer > 0) {
723 2
            $summer = self::FACT($summer);
724
725 2
            return $summer / $divisor;
726
        }
727
728
        return 0;
729
    }
730
731
    /**
732
     * ODD.
733
     *
734
     * Returns number rounded up to the nearest odd integer.
735
     *
736
     * @param float $number Number to round
737
     *
738
     * @return int Rounded Number
739
     */
740 13
    public static function ODD($number)
741
    {
742 13
        $number = Functions::flattenSingleValue($number);
743
744 13
        if ($number === null) {
745 1
            return 1;
746 12
        } elseif (is_bool($number)) {
747 2
            return 1;
748 10
        } elseif (is_numeric($number)) {
749 9
            $significance = self::SIGN($number);
750 9
            if ($significance == 0) {
751 1
                return 1;
752
            }
753
754 8
            $result = self::CEILING($number, $significance);
755 8
            if ($result == self::EVEN($result)) {
756 5
                $result += $significance;
757
            }
758
759 8
            return (int) $result;
760
        }
761
762 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
763
    }
764
765
    /**
766
     * POWER.
767
     *
768
     * Computes x raised to the power y.
769
     *
770
     * @param float $x
771
     * @param float $y
772
     *
773
     * @return float
774
     */
775 81
    public static function POWER($x = 0, $y = 2)
776
    {
777 81
        $x = Functions::flattenSingleValue($x);
778 81
        $y = Functions::flattenSingleValue($y);
779
780
        // Validate parameters
781 81
        if ($x == 0.0 && $y == 0.0) {
782 1
            return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
783 80
        } elseif ($x == 0.0 && $y < 0.0) {
784 2
            return Functions::DIV0();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...ation\Functions::DIV0() returns the type string which is incompatible with the documented return type double.
Loading history...
785
        }
786
787
        // Return
788 78
        $result = pow($x, $y);
789
790 78
        return (!is_nan($result) && !is_infinite($result)) ? $result : Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return ! is_nan($result)...lation\Functions::NAN() also could return the type string which is incompatible with the documented return type double.
Loading history...
791
    }
792
793
    /**
794
     * PRODUCT.
795
     *
796
     * PRODUCT returns the product of all the values and cells referenced in the argument list.
797
     *
798
     * Excel Function:
799
     *        PRODUCT(value1[,value2[, ...]])
800
     *
801
     * @category Mathematical and Trigonometric Functions
802
     *
803
     * @param mixed ...$args Data values
804
     *
805
     * @return float
806
     */
807 11
    public static function PRODUCT(...$args)
808
    {
809
        // Return value
810 11
        $returnValue = null;
811
812
        // Loop through arguments
813 11
        foreach (Functions::flattenArray($args) as $arg) {
814
            // Is it a numeric value?
815 11
            if ((is_numeric($arg)) && (!is_string($arg))) {
816 11
                if ($returnValue === null) {
817 11
                    $returnValue = $arg;
818
                } else {
819 11
                    $returnValue *= $arg;
820
                }
821
            }
822
        }
823
824
        // Return
825 11
        if ($returnValue === null) {
826
            return 0;
827
        }
828
829 11
        return $returnValue;
830
    }
831
832
    /**
833
     * QUOTIENT.
834
     *
835
     * QUOTIENT function returns the integer portion of a division. Numerator is the divided number
836
     *        and denominator is the divisor.
837
     *
838
     * Excel Function:
839
     *        QUOTIENT(value1[,value2[, ...]])
840
     *
841
     * @category Mathematical and Trigonometric Functions
842
     *
843
     * @param mixed ...$args Data values
844
     *
845
     * @return float
846
     */
847 6
    public static function QUOTIENT(...$args)
848
    {
849
        // Return value
850 6
        $returnValue = null;
851
852
        // Loop through arguments
853 6
        foreach (Functions::flattenArray($args) as $arg) {
854
            // Is it a numeric value?
855 6
            if ((is_numeric($arg)) && (!is_string($arg))) {
856 6
                if ($returnValue === null) {
857 6
                    $returnValue = ($arg == 0) ? 0 : $arg;
858
                } else {
859 6
                    if (($returnValue == 0) || ($arg == 0)) {
860
                        $returnValue = 0;
861
                    } else {
862 6
                        $returnValue /= $arg;
863
                    }
864
                }
865
            }
866
        }
867
868
        // Return
869 6
        return (int) $returnValue;
870
    }
871
872
    /**
873
     * RAND.
874
     *
875
     * @param int $min Minimal value
876
     * @param int $max Maximal value
877
     *
878
     * @return int Random number
879
     */
880 3
    public static function RAND($min = 0, $max = 0)
881
    {
882 3
        $min = Functions::flattenSingleValue($min);
883 3
        $max = Functions::flattenSingleValue($max);
884
885 3
        if ($min == 0 && $max == 0) {
886 1
            return (mt_rand(0, 10000000)) / 10000000;
887
        }
888
889 3
        return mt_rand($min, $max);
890
    }
891
892 6
    public static function ROMAN($aValue, $style = 0)
893
    {
894 6
        $aValue = Functions::flattenSingleValue($aValue);
895 6
        $style = ($style === null) ? 0 : (int) Functions::flattenSingleValue($style);
0 ignored issues
show
Unused Code introduced by
The assignment to $style is dead and can be removed.
Loading history...
896 6
        if ((!is_numeric($aValue)) || ($aValue < 0) || ($aValue >= 4000)) {
897
            return Functions::VALUE();
898
        }
899 6
        $aValue = (int) $aValue;
900 6
        if ($aValue == 0) {
901
            return '';
902
        }
903
904 6
        $mill = ['', 'M', 'MM', 'MMM', 'MMMM', 'MMMMM'];
905 6
        $cent = ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'];
906 6
        $tens = ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'];
907 6
        $ones = ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'];
908
909 6
        $roman = '';
910 6
        while ($aValue > 5999) {
911
            $roman .= 'M';
912
            $aValue -= 1000;
913
        }
914 6
        $m = self::romanCut($aValue, 1000);
915 6
        $aValue %= 1000;
916 6
        $c = self::romanCut($aValue, 100);
917 6
        $aValue %= 100;
918 6
        $t = self::romanCut($aValue, 10);
919 6
        $aValue %= 10;
920
921 6
        return $roman . $mill[$m] . $cent[$c] . $tens[$t] . $ones[$aValue];
922
    }
923
924
    /**
925
     * ROUNDUP.
926
     *
927
     * Rounds a number up to a specified number of decimal places
928
     *
929
     * @param float $number Number to round
930
     * @param int $digits Number of digits to which you want to round $number
931
     *
932
     * @return float Rounded Number
933
     */
934 14
    public static function ROUNDUP($number, $digits)
935
    {
936 14
        $number = Functions::flattenSingleValue($number);
937 14
        $digits = Functions::flattenSingleValue($digits);
938
939 14
        if ((is_numeric($number)) && (is_numeric($digits))) {
940 12
            $significance = pow(10, (int) $digits);
941 12
            if ($number < 0.0) {
942 2
                return floor($number * $significance) / $significance;
943
            }
944
945 10
            return ceil($number * $significance) / $significance;
946
        }
947
948 2
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
949
    }
950
951
    /**
952
     * ROUNDDOWN.
953
     *
954
     * Rounds a number down to a specified number of decimal places
955
     *
956
     * @param float $number Number to round
957
     * @param int $digits Number of digits to which you want to round $number
958
     *
959
     * @return float Rounded Number
960
     */
961 14
    public static function ROUNDDOWN($number, $digits)
962
    {
963 14
        $number = Functions::flattenSingleValue($number);
964 14
        $digits = Functions::flattenSingleValue($digits);
965
966 14
        if ((is_numeric($number)) && (is_numeric($digits))) {
967 12
            $significance = pow(10, (int) $digits);
968 12
            if ($number < 0.0) {
969 2
                return ceil($number * $significance) / $significance;
970
            }
971
972 10
            return floor($number * $significance) / $significance;
973
        }
974
975 2
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
976
    }
977
978
    /**
979
     * SERIESSUM.
980
     *
981
     * Returns the sum of a power series
982
     *
983
     * @param float $x Input value to the power series
984
     * @param float $n Initial power to which you want to raise $x
985
     * @param float $m Step by which to increase $n for each term in the series
986
     * @param array of mixed Data Series
987
     *
988
     * @return float
989
     */
990 2
    public static function SERIESSUM(...$args)
991
    {
992 2
        $returnValue = 0;
993
994
        // Loop through arguments
995 2
        $aArgs = Functions::flattenArray($args);
996
997 2
        $x = array_shift($aArgs);
998 2
        $n = array_shift($aArgs);
999 2
        $m = array_shift($aArgs);
1000
1001 2
        if ((is_numeric($x)) && (is_numeric($n)) && (is_numeric($m))) {
1002
            // Calculate
1003 2
            $i = 0;
1004 2
            foreach ($aArgs as $arg) {
1005
                // Is it a numeric value?
1006 2
                if ((is_numeric($arg)) && (!is_string($arg))) {
1007 2
                    $returnValue += $arg * pow($x, $n + ($m * $i++));
1008
                } else {
1009
                    return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
1010
                }
1011
            }
1012
1013 2
            return $returnValue;
1014
        }
1015
1016
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
1017
    }
1018
1019
    /**
1020
     * SIGN.
1021
     *
1022
     * Determines the sign of a number. Returns 1 if the number is positive, zero (0)
1023
     *        if the number is 0, and -1 if the number is negative.
1024
     *
1025
     * @param float $number Number to round
1026
     *
1027
     * @return int sign value
1028
     */
1029 72
    public static function SIGN($number)
1030
    {
1031 72
        $number = Functions::flattenSingleValue($number);
1032
1033 72
        if (is_bool($number)) {
1034 2
            return (int) $number;
1035
        }
1036 70
        if (is_numeric($number)) {
1037 69
            if ($number == 0.0) {
1038 4
                return 0;
1039
            }
1040
1041 65
            return $number / abs($number);
1042
        }
1043
1044 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type integer.
Loading history...
1045
    }
1046
1047
    /**
1048
     * SQRTPI.
1049
     *
1050
     * Returns the square root of (number * pi).
1051
     *
1052
     * @param float $number Number
1053
     *
1054
     * @return float Square Root of Number * Pi
1055
     */
1056 15
    public static function SQRTPI($number)
1057
    {
1058 15
        $number = Functions::flattenSingleValue($number);
1059
1060 15
        if (is_numeric($number)) {
1061 14
            if ($number < 0) {
1062 3
                return Functions::NAN();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...lation\Functions::NAN() returns the type string which is incompatible with the documented return type double.
Loading history...
1063
            }
1064
1065 11
            return sqrt($number * M_PI);
1066
        }
1067
1068 1
        return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
1069
    }
1070
1071 11
    protected static function filterHiddenArgs($cellReference, $args)
1072
    {
1073 11
        return array_filter(
1074 11
            $args,
1075
            function ($index) use ($cellReference) {
1076 11
                [, $row, $column] = explode('.', $index);
1077
1078 11
                return $cellReference->getWorksheet()->getRowDimension($row)->getVisible() &&
1079 11
                    $cellReference->getWorksheet()->getColumnDimension($column)->getVisible();
1080 11
            },
1081 11
            ARRAY_FILTER_USE_KEY
1082
        );
1083
    }
1084
1085 23
    protected static function filterFormulaArgs($cellReference, $args)
1086
    {
1087 23
        return array_filter(
1088 23
            $args,
1089
            function ($index) use ($cellReference) {
1090 23
                [, $row, $column] = explode('.', $index);
1091 23
                if ($cellReference->getWorksheet()->cellExists($column . $row)) {
1092
                    //take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
1093 23
                    $isFormula = $cellReference->getWorksheet()->getCell($column . $row)->isFormula();
1094 23
                    $cellFormula = !preg_match('/^=.*\b(SUBTOTAL|AGGREGATE)\s*\(/i', $cellReference->getWorksheet()->getCell($column . $row)->getValue());
1095
1096 23
                    return !$isFormula || $cellFormula;
1097
                }
1098
1099
                return true;
1100 23
            },
1101 23
            ARRAY_FILTER_USE_KEY
1102
        );
1103
    }
1104
1105
    /**
1106
     * SUBTOTAL.
1107
     *
1108
     * Returns a subtotal in a list or database.
1109
     *
1110
     * @param int the number 1 to 11 that specifies which function to
0 ignored issues
show
Bug introduced by
The type PhpOffice\PhpSpreadsheet\Calculation\the was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
1111
     *                    use in calculating subtotals within a range
1112
     *                    list
1113
     *            Numbers 101 to 111 shadow the functions of 1 to 11
1114
     *                    but ignore any values in the range that are
1115
     *                    in hidden rows or columns
1116
     * @param array of mixed Data Series
1117
     *
1118
     * @return float|string
1119
     */
1120 23
    public static function SUBTOTAL(...$args)
1121
    {
1122 23
        $cellReference = array_pop($args);
1123 23
        $aArgs = Functions::flattenArrayIndexed($args);
1124 23
        $subtotal = array_shift($aArgs);
1125
1126
        // Calculate
1127 23
        if ((is_numeric($subtotal)) && (!is_string($subtotal))) {
1128 23
            if ($subtotal > 100) {
1129 11
                $aArgs = self::filterHiddenArgs($cellReference, $aArgs);
1130 11
                $subtotal -= 100;
1131
            }
1132
1133 23
            $aArgs = self::filterFormulaArgs($cellReference, $aArgs);
1134 23
            switch ($subtotal) {
1135 23
                case 1:
1136 2
                    return Statistical::AVERAGE($aArgs);
1137 21
                case 2:
1138 2
                    return Statistical::COUNT($aArgs);
1139 19
                case 3:
1140 2
                    return Statistical::COUNTA($aArgs);
1141 17
                case 4:
1142 2
                    return Statistical::MAX($aArgs);
1143 15
                case 5:
1144 2
                    return Statistical::MIN($aArgs);
1145 13
                case 6:
1146 2
                    return self::PRODUCT($aArgs);
1147 11
                case 7:
1148 2
                    return Statistical::STDEV($aArgs);
1149 9
                case 8:
1150 2
                    return Statistical::STDEVP($aArgs);
1151 7
                case 9:
1152 3
                    return self::SUM($aArgs);
1153 4
                case 10:
1154 2
                    return Statistical::VARFunc($aArgs);
1155 2
                case 11:
1156 2
                    return Statistical::VARP($aArgs);
1157
            }
1158
        }
1159
1160
        return Functions::VALUE();
1161
    }
1162
1163
    /**
1164
     * SUM.
1165
     *
1166
     * SUM computes the sum of all the values and cells referenced in the argument list.
1167
     *
1168
     * Excel Function:
1169
     *        SUM(value1[,value2[, ...]])
1170
     *
1171
     * @category Mathematical and Trigonometric Functions
1172
     *
1173
     * @param mixed ...$args Data values
1174
     *
1175
     * @return float
1176
     */
1177 32
    public static function SUM(...$args)
1178
    {
1179 32
        $returnValue = 0;
1180
1181
        // Loop through the arguments
1182 32
        foreach (Functions::flattenArray($args) as $arg) {
1183
            // Is it a numeric value?
1184 32
            if ((is_numeric($arg)) && (!is_string($arg))) {
1185 32
                $returnValue += $arg;
1186
            }
1187
        }
1188
1189 32
        return $returnValue;
1190
    }
1191
1192
    /**
1193
     * SUMIF.
1194
     *
1195
     * Counts the number of cells that contain numbers within the list of arguments
1196
     *
1197
     * Excel Function:
1198
     *        SUMIF(value1[,value2[, ...]],condition)
1199
     *
1200
     * @category Mathematical and Trigonometric Functions
1201
     *
1202
     * @param mixed $aArgs Data values
1203
     * @param string $condition the criteria that defines which cells will be summed
1204
     * @param mixed $sumArgs
1205
     *
1206
     * @return float
1207
     */
1208 10
    public static function SUMIF($aArgs, $condition, $sumArgs = [])
1209
    {
1210 10
        $returnValue = 0;
1211
1212 10
        $aArgs = Functions::flattenArray($aArgs);
1213 10
        $sumArgs = Functions::flattenArray($sumArgs);
1214 10
        if (empty($sumArgs)) {
1215 1
            $sumArgs = $aArgs;
1216
        }
1217 10
        $condition = Functions::ifCondition($condition);
1218
        // Loop through arguments
1219 10
        foreach ($aArgs as $key => $arg) {
1220 10
            if (!is_numeric($arg)) {
1221 6
                $arg = str_replace('"', '""', $arg);
1222 6
                $arg = Calculation::wrapResult(strtoupper($arg));
1223
            }
1224
1225 10
            $testCondition = '=' . $arg . $condition;
1226 10
            $sumValue = array_key_exists($key, $sumArgs) ? $sumArgs[$key] : 0;
1227
1228 10
            if (is_numeric($sumValue) &&
1229 10
                Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
1230
                // Is it a value within our criteria and only numeric can be added to the result
1231 10
                $returnValue += $sumValue;
1232
            }
1233
        }
1234
1235 10
        return $returnValue;
1236
    }
1237
1238
    /**
1239
     * SUMIFS.
1240
     *
1241
     *    Counts the number of cells that contain numbers within the list of arguments
1242
     *
1243
     *    Excel Function:
1244
     *        SUMIFS(value1[,value2[, ...]],condition)
1245
     *
1246
     *    @category Mathematical and Trigonometric Functions
1247
     *
1248
     * @param mixed $args Data values
1249
     * @param string $condition the criteria that defines which cells will be summed
1250
     *
1251
     * @return float
1252
     */
1253 2
    public static function SUMIFS(...$args)
1254
    {
1255 2
        $arrayList = $args;
1256
1257
        // Return value
1258 2
        $returnValue = 0;
1259
1260 2
        $sumArgs = Functions::flattenArray(array_shift($arrayList));
1261 2
        $aArgsArray = [];
1262 2
        $conditions = [];
1263
1264 2
        while (count($arrayList) > 0) {
1265 2
            $aArgsArray[] = Functions::flattenArray(array_shift($arrayList));
1266 2
            $conditions[] = Functions::ifCondition(array_shift($arrayList));
1267
        }
1268
1269
        // Loop through each sum and see if arguments and conditions are true
1270 2
        foreach ($sumArgs as $index => $value) {
1271 2
            $valid = true;
1272
1273 2
            foreach ($conditions as $cidx => $condition) {
1274 2
                $arg = $aArgsArray[$cidx][$index];
1275
1276
                // Loop through arguments
1277 2
                if (!is_numeric($arg)) {
1278 2
                    $arg = Calculation::wrapResult(strtoupper($arg));
1279
                }
1280 2
                $testCondition = '=' . $arg . $condition;
1281 2
                if (!Calculation::getInstance()->_calculateFormulaValue($testCondition)) {
1282
                    // Is not a value within our criteria
1283 2
                    $valid = false;
1284
1285 2
                    break; // if false found, don't need to check other conditions
1286
                }
1287
            }
1288
1289 2
            if ($valid) {
1290 2
                $returnValue += $value;
1291
            }
1292
        }
1293
1294
        // Return
1295 2
        return $returnValue;
1296
    }
1297
1298
    /**
1299
     * SUMPRODUCT.
1300
     *
1301
     * Excel Function:
1302
     *        SUMPRODUCT(value1[,value2[, ...]])
1303
     *
1304
     * @category Mathematical and Trigonometric Functions
1305
     *
1306
     * @param mixed ...$args Data values
1307
     *
1308
     * @return float
1309
     */
1310 3
    public static function SUMPRODUCT(...$args)
1311
    {
1312 3
        $arrayList = $args;
1313
1314 3
        $wrkArray = Functions::flattenArray(array_shift($arrayList));
1315 3
        $wrkCellCount = count($wrkArray);
1316
1317 3
        for ($i = 0; $i < $wrkCellCount; ++$i) {
1318 3
            if ((!is_numeric($wrkArray[$i])) || (is_string($wrkArray[$i]))) {
1319
                $wrkArray[$i] = 0;
1320
            }
1321
        }
1322
1323 3
        foreach ($arrayList as $matrixData) {
1324 3
            $array2 = Functions::flattenArray($matrixData);
1325 3
            $count = count($array2);
1326 3
            if ($wrkCellCount != $count) {
1327
                return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
1328
            }
1329
1330 3
            foreach ($array2 as $i => $val) {
1331 3
                if ((!is_numeric($val)) || (is_string($val))) {
1332
                    $val = 0;
1333
                }
1334 3
                $wrkArray[$i] *= $val;
1335
            }
1336
        }
1337
1338 3
        return array_sum($wrkArray);
1339
    }
1340
1341
    /**
1342
     * SUMSQ.
1343
     *
1344
     * SUMSQ returns the sum of the squares of the arguments
1345
     *
1346
     * Excel Function:
1347
     *        SUMSQ(value1[,value2[, ...]])
1348
     *
1349
     * @category Mathematical and Trigonometric Functions
1350
     *
1351
     * @param mixed ...$args Data values
1352
     *
1353
     * @return float
1354
     */
1355 7
    public static function SUMSQ(...$args)
1356
    {
1357 7
        $returnValue = 0;
1358
1359
        // Loop through arguments
1360 7
        foreach (Functions::flattenArray($args) as $arg) {
1361
            // Is it a numeric value?
1362 7
            if ((is_numeric($arg)) && (!is_string($arg))) {
1363 7
                $returnValue += ($arg * $arg);
1364
            }
1365
        }
1366
1367 7
        return $returnValue;
1368
    }
1369
1370
    /**
1371
     * SUMX2MY2.
1372
     *
1373
     * @param mixed[] $matrixData1 Matrix #1
1374
     * @param mixed[] $matrixData2 Matrix #2
1375
     *
1376
     * @return float
1377
     */
1378 3
    public static function SUMX2MY2($matrixData1, $matrixData2)
1379
    {
1380 3
        $array1 = Functions::flattenArray($matrixData1);
1381 3
        $array2 = Functions::flattenArray($matrixData2);
1382 3
        $count = min(count($array1), count($array2));
1383
1384 3
        $result = 0;
1385 3
        for ($i = 0; $i < $count; ++$i) {
1386 3
            if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
1387 3
                ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
1388 3
                $result += ($array1[$i] * $array1[$i]) - ($array2[$i] * $array2[$i]);
1389
            }
1390
        }
1391
1392 3
        return $result;
1393
    }
1394
1395
    /**
1396
     * SUMX2PY2.
1397
     *
1398
     * @param mixed[] $matrixData1 Matrix #1
1399
     * @param mixed[] $matrixData2 Matrix #2
1400
     *
1401
     * @return float
1402
     */
1403 3
    public static function SUMX2PY2($matrixData1, $matrixData2)
1404
    {
1405 3
        $array1 = Functions::flattenArray($matrixData1);
1406 3
        $array2 = Functions::flattenArray($matrixData2);
1407 3
        $count = min(count($array1), count($array2));
1408
1409 3
        $result = 0;
1410 3
        for ($i = 0; $i < $count; ++$i) {
1411 3
            if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
1412 3
                ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
1413 3
                $result += ($array1[$i] * $array1[$i]) + ($array2[$i] * $array2[$i]);
1414
            }
1415
        }
1416
1417 3
        return $result;
1418
    }
1419
1420
    /**
1421
     * SUMXMY2.
1422
     *
1423
     * @param mixed[] $matrixData1 Matrix #1
1424
     * @param mixed[] $matrixData2 Matrix #2
1425
     *
1426
     * @return float
1427
     */
1428 3
    public static function SUMXMY2($matrixData1, $matrixData2)
1429
    {
1430 3
        $array1 = Functions::flattenArray($matrixData1);
1431 3
        $array2 = Functions::flattenArray($matrixData2);
1432 3
        $count = min(count($array1), count($array2));
1433
1434 3
        $result = 0;
1435 3
        for ($i = 0; $i < $count; ++$i) {
1436 3
            if (((is_numeric($array1[$i])) && (!is_string($array1[$i]))) &&
1437 3
                ((is_numeric($array2[$i])) && (!is_string($array2[$i])))) {
1438 3
                $result += ($array1[$i] - $array2[$i]) * ($array1[$i] - $array2[$i]);
1439
            }
1440
        }
1441
1442 3
        return $result;
1443
    }
1444
1445
    /**
1446
     * TRUNC.
1447
     *
1448
     * Truncates value to the number of fractional digits by number_digits.
1449
     *
1450
     * @param float $value
1451
     * @param int $digits
1452
     *
1453
     * @return float Truncated value
1454
     */
1455 19
    public static function TRUNC($value = 0, $digits = 0)
1456
    {
1457 19
        $value = Functions::flattenSingleValue($value);
1458 19
        $digits = Functions::flattenSingleValue($digits);
1459
1460
        // Validate parameters
1461 19
        if ((!is_numeric($value)) || (!is_numeric($digits))) {
1462 2
            return Functions::VALUE();
0 ignored issues
show
Bug Best Practice introduced by
The expression return PhpOffice\PhpSpre...tion\Functions::VALUE() returns the type string which is incompatible with the documented return type double.
Loading history...
1463
        }
1464 17
        $digits = floor($digits);
1465
1466
        // Truncate
1467 17
        $adjust = pow(10, $digits);
1468
1469 17
        if (($digits > 0) && (rtrim((int) ((abs($value) - abs((int) $value)) * $adjust), '0') < $adjust / 10)) {
1470 2
            return $value;
1471
        }
1472
1473 15
        return ((int) ($value * $adjust)) / $adjust;
1474
    }
1475
1476
    /**
1477
     * SEC.
1478
     *
1479
     * Returns the secant of an angle.
1480
     *
1481
     * @param float $angle Number
1482
     *
1483
     * @return float|string The secant of the angle
1484
     */
1485 14
    public static function SEC($angle)
1486
    {
1487 14
        $angle = Functions::flattenSingleValue($angle);
1488
1489 14
        if (!is_numeric($angle)) {
1490 1
            return Functions::VALUE();
1491
        }
1492
1493 13
        $result = cos($angle);
1494
1495 13
        return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
1496
    }
1497
1498
    /**
1499
     * SECH.
1500
     *
1501
     * Returns the hyperbolic secant of an angle.
1502
     *
1503
     * @param float $angle Number
1504
     *
1505
     * @return float|string The hyperbolic secant of the angle
1506
     */
1507 14
    public static function SECH($angle)
1508
    {
1509 14
        $angle = Functions::flattenSingleValue($angle);
1510
1511 14
        if (!is_numeric($angle)) {
1512 1
            return Functions::VALUE();
1513
        }
1514
1515 13
        $result = cosh($angle);
1516
1517 13
        return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
1518
    }
1519
1520
    /**
1521
     * CSC.
1522
     *
1523
     * Returns the cosecant of an angle.
1524
     *
1525
     * @param float $angle Number
1526
     *
1527
     * @return float|string The cosecant of the angle
1528
     */
1529 10
    public static function CSC($angle)
1530
    {
1531 10
        $angle = Functions::flattenSingleValue($angle);
1532
1533 10
        if (!is_numeric($angle)) {
1534 1
            return Functions::VALUE();
1535
        }
1536
1537 9
        $result = sin($angle);
1538
1539 9
        return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
1540
    }
1541
1542
    /**
1543
     * CSCH.
1544
     *
1545
     * Returns the hyperbolic cosecant of an angle.
1546
     *
1547
     * @param float $angle Number
1548
     *
1549
     * @return float|string The hyperbolic cosecant of the angle
1550
     */
1551 14
    public static function CSCH($angle)
1552
    {
1553 14
        $angle = Functions::flattenSingleValue($angle);
1554
1555 14
        if (!is_numeric($angle)) {
1556 1
            return Functions::VALUE();
1557
        }
1558
1559 13
        $result = sinh($angle);
1560
1561 13
        return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
1562
    }
1563
1564
    /**
1565
     * COT.
1566
     *
1567
     * Returns the cotangent of an angle.
1568
     *
1569
     * @param float $angle Number
1570
     *
1571
     * @return float|string The cotangent of the angle
1572
     */
1573 10
    public static function COT($angle)
1574
    {
1575 10
        $angle = Functions::flattenSingleValue($angle);
1576
1577 10
        if (!is_numeric($angle)) {
1578 1
            return Functions::VALUE();
1579
        }
1580
1581 9
        $result = tan($angle);
1582
1583 9
        return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
1584
    }
1585
1586
    /**
1587
     * COTH.
1588
     *
1589
     * Returns the hyperbolic cotangent of an angle.
1590
     *
1591
     * @param float $angle Number
1592
     *
1593
     * @return float|string The hyperbolic cotangent of the angle
1594
     */
1595 14
    public static function COTH($angle)
1596
    {
1597 14
        $angle = Functions::flattenSingleValue($angle);
1598
1599 14
        if (!is_numeric($angle)) {
1600 1
            return Functions::VALUE();
1601
        }
1602
1603 13
        $result = tanh($angle);
1604
1605 13
        return ($result == 0.0) ? Functions::DIV0() : 1 / $result;
1606
    }
1607
1608
    /**
1609
     * ACOT.
1610
     *
1611
     * Returns the arccotangent of a number.
1612
     *
1613
     * @param float $number Number
1614
     *
1615
     * @return float|string The arccotangent of the number
1616
     */
1617 14
    public static function ACOT($number)
1618
    {
1619 14
        $number = Functions::flattenSingleValue($number);
1620
1621 14
        if (!is_numeric($number)) {
1622 1
            return Functions::VALUE();
1623
        }
1624
1625 13
        return (M_PI / 2) - atan($number);
1626
    }
1627
1628
    /**
1629
     * ACOTH.
1630
     *
1631
     * Returns the hyperbolic arccotangent of a number.
1632
     *
1633
     * @param float $number Number
1634
     *
1635
     * @return float|string The hyperbolic arccotangent of the number
1636
     */
1637 14
    public static function ACOTH($number)
1638
    {
1639 14
        $number = Functions::flattenSingleValue($number);
1640
1641 14
        if (!is_numeric($number)) {
1642 1
            return Functions::VALUE();
1643
        }
1644
1645 13
        $result = log(($number + 1) / ($number - 1)) / 2;
1646
1647 13
        return is_nan($result) ? Functions::NAN() : $result;
1648
    }
1649
}
1650