Skip to content

Commit 92ce3ae

Browse files
committed
Add 4 new rounding modes to round() function
1 parent b56141c commit 92ce3ae

File tree

6 files changed

+413
-39
lines changed

6 files changed

+413
-39
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Standard:
2525
. Partly fix GH-12143 (Incorrect round() result for 0.49999999999999994).
2626
(timwolla)
2727
. Fix GH-12252 (round(): Validate the rounding mode). (timwolla)
28+
. Added 4 new rounding modes to the round(). (Jorg Sowa)
29+
2830

2931
XSL:
3032
. Implement request #64137 (XSLTProcessor::setParameter() should allow both

ext/standard/basic_functions.stub.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,26 @@
375375
* @cvalue PHP_ROUND_HALF_ODD
376376
*/
377377
const PHP_ROUND_HALF_ODD = UNKNOWN;
378+
/**
379+
* @var int
380+
* @cvalue PHP_ROUND_CEILING
381+
*/
382+
const PHP_ROUND_CEILING = UNKNOWN;
383+
/**
384+
* @var int
385+
* @cvalue PHP_ROUND_FLOOR
386+
*/
387+
const PHP_ROUND_FLOOR = UNKNOWN;
388+
/**
389+
* @var int
390+
* @cvalue PHP_ROUND_TOWARD_ZERO
391+
*/
392+
const PHP_ROUND_TOWARD_ZERO = UNKNOWN;
393+
/**
394+
* @var int
395+
* @cvalue PHP_ROUND_AWAY_FROM_ZERO
396+
*/
397+
const PHP_ROUND_AWAY_FROM_ZERO = UNKNOWN;
378398

379399
/* crypt.c */
380400

ext/standard/basic_functions_arginfo.h

Lines changed: 5 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/math.c

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ static inline double php_round_helper(double value, int mode) {
101101
* the absolute value of the fractional part (which will not result
102102
* in branches in the assembly) to make the following cases simpler.
103103
*/
104-
fractional = fabs(modf(value, &integral));
105104

106105
switch (mode) {
107106
case PHP_ROUND_HALF_UP:
107+
fractional = fabs(modf(value, &integral));
108108
if (fractional >= 0.5) {
109109
/* We must increase the magnitude of the integral part
110110
* (rounding up / towards infinity). copysign(1.0, integral)
@@ -120,13 +120,35 @@ static inline double php_round_helper(double value, int mode) {
120120
return integral;
121121

122122
case PHP_ROUND_HALF_DOWN:
123+
fractional = fabs(modf(value, &integral));
123124
if (fractional > 0.5) {
124125
return integral + copysign(1.0, integral);
125126
}
126127

127128
return integral;
128129

130+
case PHP_ROUND_CEILING:
131+
return ceil(value);
132+
133+
case PHP_ROUND_FLOOR:
134+
return floor(value);
135+
136+
case PHP_ROUND_TOWARD_ZERO:
137+
if (value >= 0.0) {
138+
return floor(value);
139+
} else {
140+
return = ceil(value);
141+
}
142+
143+
case PHP_ROUND_AWAY_FROM_ZERO:
144+
if (value >= 0.0) {
145+
return = ceil(value);
146+
} else {
147+
return = floor(value);
148+
}
149+
129150
case PHP_ROUND_HALF_EVEN:
151+
fractional = fabs(modf(value, &integral));
130152
if (fractional > 0.5) {
131153
return integral + copysign(1.0, integral);
132154
}
@@ -143,7 +165,9 @@ static inline double php_round_helper(double value, int mode) {
143165
}
144166

145167
return integral;
168+
146169
case PHP_ROUND_HALF_ODD:
170+
fractional = fabs(modf(value, &integral));
147171
if (fractional > 0.5) {
148172
return integral + copysign(1.0, integral);
149173
}
@@ -157,6 +181,7 @@ static inline double php_round_helper(double value, int mode) {
157181
}
158182

159183
return integral;
184+
160185
EMPTY_SWITCH_DEFAULT_CASE();
161186
}
162187
}
@@ -258,16 +283,16 @@ PHP_FUNCTION(abs)
258283
Z_PARAM_NUMBER(value)
259284
ZEND_PARSE_PARAMETERS_END();
260285

261-
switch (Z_TYPE_P(value)) {
262-
case IS_LONG:
263-
if (UNEXPECTED(Z_LVAL_P(value) == ZEND_LONG_MIN)) {
264-
RETURN_DOUBLE(-(double)ZEND_LONG_MIN);
265-
} else {
266-
RETURN_LONG(Z_LVAL_P(value) < 0 ? -Z_LVAL_P(value) : Z_LVAL_P(value));
267-
}
268-
case IS_DOUBLE:
269-
RETURN_DOUBLE(fabs(Z_DVAL_P(value)));
270-
EMPTY_SWITCH_DEFAULT_CASE();
286+
if (Z_TYPE_P(value) == IS_DOUBLE) {
287+
RETURN_DOUBLE(fabs(Z_DVAL_P(value)));
288+
} else if (Z_TYPE_P(value) == IS_LONG) {
289+
if (Z_LVAL_P(value) == ZEND_LONG_MIN) {
290+
RETURN_DOUBLE(-(double)ZEND_LONG_MIN);
291+
} else {
292+
RETURN_LONG(Z_LVAL_P(value) < 0 ? -Z_LVAL_P(value) : Z_LVAL_P(value));
293+
}
294+
} else {
295+
ZEND_ASSERT(0 && "Unexpected type");
271296
}
272297
}
273298
/* }}} */
@@ -281,12 +306,12 @@ PHP_FUNCTION(ceil)
281306
Z_PARAM_NUMBER(value)
282307
ZEND_PARSE_PARAMETERS_END();
283308

284-
switch (Z_TYPE_P(value)) {
285-
case IS_LONG:
286-
RETURN_DOUBLE(zval_get_double(value));
287-
case IS_DOUBLE:
288-
RETURN_DOUBLE(ceil(Z_DVAL_P(value)));
289-
EMPTY_SWITCH_DEFAULT_CASE();
309+
if (Z_TYPE_P(value) == IS_DOUBLE) {
310+
RETURN_DOUBLE(ceil(Z_DVAL_P(value)));
311+
} else if (Z_TYPE_P(value) == IS_LONG) {
312+
RETURN_DOUBLE(zval_get_double(value));
313+
} else {
314+
ZEND_ASSERT(0 && "Unexpected type");
290315
}
291316
}
292317
/* }}} */
@@ -300,12 +325,12 @@ PHP_FUNCTION(floor)
300325
Z_PARAM_NUMBER(value)
301326
ZEND_PARSE_PARAMETERS_END();
302327

303-
switch (Z_TYPE_P(value)) {
304-
case IS_LONG:
305-
RETURN_DOUBLE(zval_get_double(value));
306-
case IS_DOUBLE:
307-
RETURN_DOUBLE(floor(Z_DVAL_P(value)));
308-
EMPTY_SWITCH_DEFAULT_CASE();
328+
if (Z_TYPE_P(value) == IS_DOUBLE) {
329+
RETURN_DOUBLE(floor(Z_DVAL_P(value)));
330+
} else if (Z_TYPE_P(value) == IS_LONG) {
331+
RETURN_DOUBLE(zval_get_double(value));
332+
} else {
333+
ZEND_ASSERT(0 && "Unexpected type");
309334
}
310335
}
311336
/* }}} */
@@ -317,6 +342,7 @@ PHP_FUNCTION(round)
317342
int places = 0;
318343
zend_long precision = 0;
319344
zend_long mode = PHP_ROUND_HALF_UP;
345+
double return_val;
320346

321347
ZEND_PARSE_PARAMETERS_START(1, 3)
322348
Z_PARAM_NUMBER(value)
@@ -333,29 +359,21 @@ PHP_FUNCTION(round)
333359
}
334360
}
335361

336-
switch (mode) {
337-
case PHP_ROUND_HALF_UP:
338-
case PHP_ROUND_HALF_DOWN:
339-
case PHP_ROUND_HALF_EVEN:
340-
case PHP_ROUND_HALF_ODD:
341-
break;
342-
default:
343-
zend_argument_value_error(3, "must be a valid rounding mode (PHP_ROUND_*)");
344-
RETURN_THROWS();
345-
}
346-
347362
switch (Z_TYPE_P(value)) {
348363
case IS_LONG:
349364
/* Simple case - long that doesn't need to be rounded. */
350365
if (places >= 0) {
351-
RETURN_DOUBLE(zval_get_double(value));
366+
RETURN_DOUBLE((double) Z_LVAL_P(value));
352367
}
353368
ZEND_FALLTHROUGH;
354369

355370
case IS_DOUBLE:
356-
RETURN_DOUBLE(_php_math_round(zval_get_double(value), (int)places, (int)mode));
371+
return_val = (Z_TYPE_P(value) == IS_LONG) ? (double)Z_LVAL_P(value) : Z_DVAL_P(value);
372+
return_val = _php_math_round(return_val, (int)places, (int)mode);
373+
RETURN_DOUBLE(return_val);
374+
break;
357375

358-
EMPTY_SWITCH_DEFAULT_CASE();
376+
EMPTY_SWITCH_DEFAULT_CASE()
359377
}
360378
}
361379
/* }}} */

ext/standard/php_math.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base);
103103
#endif
104104

105105
#ifndef PHP_ROUND_HALF_DOWN
106-
#define PHP_ROUND_HALF_DOWN 0x02 /* Down == towards zero */
106+
#define PHP_ROUND_HALF_DOWN 0x02 /* Arithmetic rounding, down == towards zero */
107107
#endif
108108

109109
#ifndef PHP_ROUND_HALF_EVEN
@@ -114,4 +114,20 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base);
114114
#define PHP_ROUND_HALF_ODD 0x04
115115
#endif
116116

117+
#ifndef PHP_ROUND_CEILING
118+
#define PHP_ROUND_CEILING 0x05
119+
#endif
120+
121+
#ifndef PHP_ROUND_FLOOR
122+
#define PHP_ROUND_FLOOR 0x06
123+
#endif
124+
125+
#ifndef PHP_ROUND_TOWARD_ZERO
126+
#define PHP_ROUND_TOWARD_ZERO 0x07
127+
#endif
128+
129+
#ifndef PHP_ROUND_AWAY_FROM_ZERO
130+
#define PHP_ROUND_AWAY_FROM_ZERO 0x08
131+
#endif
132+
117133
#endif /* PHP_MATH_H */

0 commit comments

Comments
 (0)