Passed
Pull Request — master (#4115)
by Owen
12:25
created

Round::up()   B

Complexity

Conditions 8
Paths 8

Size

Total Lines 33
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 8

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 19
dl 0
loc 33
ccs 12
cts 12
cp 1
rs 8.4444
c 1
b 0
f 0
cc 8
nc 8
nop 2
crap 8
1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Calculation\MathTrig;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
6
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
7
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
8
9
class Round
10
{
11
    use ArrayEnabled;
12
13
    /**
14
     * ROUND.
15
     *
16
     * Returns the result of builtin function round after validating args.
17
     *
18
     * @param mixed $number Should be numeric, or can be an array of numbers
19
     * @param mixed $precision Should be int, or can be an array of numbers
20
     *
21
     * @return array|float|string Rounded number
22
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
23
     *            with the same dimensions
24
     */
25
    public static function round(mixed $number, mixed $precision): array|string|float
26
    {
27 54
        if (is_array($number) || is_array($precision)) {
28
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $precision);
29 54
        }
30 25
31
        try {
32
            $number = Helpers::validateNumericNullBool($number);
33
            $precision = Helpers::validateNumericNullBool($precision);
34 54
        } catch (Exception $e) {
35 52
            return $e->getMessage();
36 3
        }
37 3
38
        return round($number, (int) $precision);
39
    }
40 51
41
    /**
42
     * ROUNDUP.
43
     *
44
     * Rounds a number up to a specified number of decimal places
45
     *
46
     * @param array|float $number Number to round, or can be an array of numbers
47
     * @param array|int $digits Number of digits to which you want to round $number, or can be an array of numbers
48
     *
49
     * @return array|float|string Rounded Number, or a string containing an error
50
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
51
     *            with the same dimensions
52
     */
53
    public static function up($number, $digits): array|string|float
54
    {
55 38
        if (is_array($number) || is_array($digits)) {
56
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $digits);
57 38
        }
58 13
59
        try {
60
            $number = Helpers::validateNumericNullBool($number);
61
            $digits = (int) Helpers::validateNumericNullSubstitution($digits, null);
62 38
        } catch (Exception $e) {
63 36
            return $e->getMessage();
64 3
        }
65 3
66
        if ($number == 0.0) {
67
            return 0.0;
68 35
        }
69 4
70
        $digitsPlus1 = $digits + 1;
71
        if ($number < 0.0) {
72 31
            if ($digitsPlus1 < 0) {
73 12
                return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN);
74
            }
75
            $result = sprintf("%.{$digitsPlus1}F", $number - 0.5 * 0.1 ** $digits);
76 25
77
            return round((float) $result, $digits, PHP_ROUND_HALF_DOWN);
78
        }
79
80
        if ($digitsPlus1 < 0) {
81
            return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_DOWN);
82
        }
83
        $result = sprintf("%.{$digitsPlus1}F", $number + 0.5 * 0.1 ** $digits);
84
85
        return round((float) $result, $digits, PHP_ROUND_HALF_DOWN);
86
    }
87
88
    /**
89
     * ROUNDDOWN.
90
     *
91 38
     * Rounds a number down to a specified number of decimal places
92
     *
93 38
     * @param array|float $number Number to round, or can be an array of numbers
94 13
     * @param array|int $digits Number of digits to which you want to round $number, or can be an array of numbers
95
     *
96
     * @return array|float|string Rounded Number, or a string containing an error
97
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
98 38
     *            with the same dimensions
99 36
     */
100 3
    public static function down($number, $digits): array|string|float
101 3
    {
102
        if (is_array($number) || is_array($digits)) {
103
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $digits);
104 35
        }
105 4
106
        try {
107
            $number = Helpers::validateNumericNullBool($number);
108 31
            $digits = (int) Helpers::validateNumericNullSubstitution($digits, null);
109 12
        } catch (Exception $e) {
110
            return $e->getMessage();
111
        }
112 25
113
        if ($number == 0.0) {
114
            return 0.0;
115
        }
116
117
        $digitsPlus1 = $digits + 1;
118
        if ($number < 0.0) {
119
            if ($digitsPlus1 < 0) {
120
                return round($number + 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP);
121
            }
122
            $result = sprintf("%.{$digitsPlus1}F", $number + 0.5 * 0.1 ** $digits);
123
124
            return round((float) $result, $digits, PHP_ROUND_HALF_UP);
125
        }
126
127 34
        if ($digitsPlus1 < 0) {
128
            return round($number - 0.5 * 0.1 ** $digits, $digits, PHP_ROUND_HALF_UP);
129 34
        }
130 13
131
        $result = sprintf("%.{$digitsPlus1}F", $number - 0.5 * 0.1 ** $digits);
132
133
        return round((float) $result, $digits, PHP_ROUND_HALF_UP);
134 34
    }
135 30
136 5
    /**
137 5
     * MROUND.
138
     *
139
     * Rounds a number to the nearest multiple of a specified value
140 29
     *
141 4
     * @param mixed $number Expect float. Number to round, or can be an array of numbers
142
     * @param mixed $multiple Expect int. Multiple to which you want to round, or can be an array of numbers.
143 25
     *
144 24
     * @return array|float|int|string Rounded Number, or a string containing an error
145
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
146 24
     *            with the same dimensions
147
     */
148
    public static function multiple(mixed $number, mixed $multiple): array|string|int|float
149 1
    {
150
        if (is_array($number) || is_array($multiple)) {
151
            return self::evaluateArrayArguments([self::class, __FUNCTION__], $number, $multiple);
152
        }
153
154
        try {
155
            $number = Helpers::validateNumericNullSubstitution($number, 0);
156
            $multiple = Helpers::validateNumericNullSubstitution($multiple, null);
157
        } catch (Exception $e) {
158
            return $e->getMessage();
159
        }
160
161
        if ($number == 0 || $multiple == 0) {
162
            return 0;
163
        }
164
        if ((Helpers::returnSign($number)) == (Helpers::returnSign($multiple))) {
165
            $multiplier = 1 / $multiple;
166
167
            return round($number * $multiplier) / $multiplier;
168
        }
169
170 23
        return ExcelError::NAN();
171
    }
172 23
173 4
    /**
174
     * EVEN.
175
     *
176
     * Returns number rounded up to the nearest even integer.
177 23
     * You can use this function for processing items that come in twos. For example,
178 1
     *        a packing crate accepts rows of one or two items. The crate is full when
179 1
     *        the number of items, rounded up to the nearest two, matches the crate's
180
     *        capacity.
181
     *
182 22
     * Excel Function:
183
     *        EVEN(number)
184
     *
185
     * @param array|float $number Number to round, or can be an array of numbers
186
     *
187
     * @return array|float|string Rounded Number, or a string containing an error
188
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
189
     *            with the same dimensions
190
     */
191
    public static function even($number): array|string|float
192
    {
193
        if (is_array($number)) {
194
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
195
        }
196 19
197
        try {
198 19
            $number = Helpers::validateNumericNullBool($number);
199 4
        } catch (Exception $e) {
200
            return $e->getMessage();
201
        }
202
203 19
        return Helpers::getEven($number);
204 1
    }
205 1
206
    /**
207
     * ODD.
208 18
     *
209 18
     * Returns number rounded up to the nearest odd integer.
210 4
     *
211
     * @param array|float $number Number to round, or can be an array of numbers
212
     *
213 14
     * @return array|float|int|string Rounded Number, or a string containing an error
214 14
     *         If an array of numbers is passed as the argument, then the returned result will also be an array
215 9
     *            with the same dimensions
216
     */
217
    public static function odd($number): array|string|int|float
218 14
    {
219
        if (is_array($number)) {
220
            return self::evaluateSingleArgumentArray([self::class, __FUNCTION__], $number);
221
        }
222
223
        try {
224
            $number = Helpers::validateNumericNullBool($number);
225
        } catch (Exception $e) {
226
            return $e->getMessage();
227
        }
228
229
        $significance = Helpers::returnSign($number);
230
        if ($significance == 0) {
231
            return 1;
232
        }
233
234
        $result = ceil($number / $significance) * $significance;
235
        if ($result == Helpers::getEven($result)) {
236
            $result += $significance;
237
        }
238
239
        return $result;
240
    }
241
}
242