Passed
Pull Request — master (#4224)
by
unknown
18:27 queued 08:16
created

Round::down()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 30
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 8.0504

Importance

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