From f29511e45902f9ba8e990b7b53dba31b17254b4c Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Thu, 13 Jul 2023 22:43:53 +0200 Subject: [PATCH 01/20] Introduce two new modes to round function --- ext/standard/basic_functions.stub.php | 10 +++++ ext/standard/basic_functions_arginfo.h | 4 +- ext/standard/math.c | 48 ++++++++++++++++-------- ext/standard/php_math.h | 8 ++++ ext/standard/tests/math/round_modes.phpt | 16 ++++++++ 5 files changed, 69 insertions(+), 17 deletions(-) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 9ce2224a78292..2020bcbb8ac9d 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -370,6 +370,16 @@ * @cvalue PHP_ROUND_HALF_ODD */ const PHP_ROUND_HALF_ODD = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_UP + */ +const PHP_ROUND_UP = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_DOWN + */ +const PHP_ROUND_DOWN = UNKNOWN; /* crypt.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 1fb54cd02d8ef..e23511f259381 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: b0767630614e040866bd7ffdaf50dd31298a64f3 */ + * Stub hash: b7c035384e0a8dcd15bee4879277c14b46ddd6e9 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -3565,6 +3565,8 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_UP", PHP_ROUND_UP, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_DOWN", PHP_ROUND_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); diff --git a/ext/standard/math.c b/ext/standard/math.c index ad2823ea49bf6..3835c4c3aabcc 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -96,22 +96,38 @@ static inline double php_intpow10(int power) { static inline double php_round_helper(double value, int mode) { double tmp_value; - if (value >= 0.0) { - tmp_value = floor(value + 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0))) - { - tmp_value = tmp_value - 1.0; - } - } else { - tmp_value = ceil(value - 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0))) - { - tmp_value = tmp_value + 1.0; - } + switch (mode) { + case PHP_ROUND_HALF_UP: + tmp_value = round(value); + break; + case PHP_ROUND_HALF_DOWN: + if (value >= 0.0) { + tmp_value = ceil(value - 0.5); + } else { + tmp_value = floor(value + 0.5); + } + break; + case PHP_ROUND_UP: + tmp_value = ceil(value); + break; + case PHP_ROUND_DOWN: + tmp_value = floor(value); + break; + case PHP_ROUND_HALF_EVEN: + tmp_value = floor(value + 0.5); + if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { + tmp_value = tmp_value - 1.0; + } + break; + case PHP_ROUND_HALF_ODD: + tmp_value = floor(value + 0.5); + if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { + tmp_value = tmp_value - 1.0; + } + break; + default: + tmp_value = round(value); + break; } return tmp_value; diff --git a/ext/standard/php_math.h b/ext/standard/php_math.h index 5d6be14b80ef8..6349681712d73 100644 --- a/ext/standard/php_math.h +++ b/ext/standard/php_math.h @@ -113,4 +113,12 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base); #define PHP_ROUND_HALF_ODD 0x04 #endif +#ifndef PHP_ROUND_UP +#define PHP_ROUND_UP 0x05 +#endif + +#ifndef PHP_ROUND_DOWN +#define PHP_ROUND_DOWN 0x06 +#endif + #endif /* PHP_MATH_H */ diff --git a/ext/standard/tests/math/round_modes.phpt b/ext/standard/tests/math/round_modes.phpt index 03479c4d908fe..f6cbdaf78d515 100644 --- a/ext/standard/tests/math/round_modes.phpt +++ b/ext/standard/tests/math/round_modes.phpt @@ -6,28 +6,42 @@ var_dump (round (2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (2.5, 0, PHP_ROUND_UP)); +var_dump (round (2.5, 0, PHP_ROUND_DOWN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (-2.5, 0, PHP_ROUND_UP)); +var_dump (round (-2.5, 0, PHP_ROUND_DOWN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (3.5, 0, PHP_ROUND_UP)); +var_dump (round (3.5, 0, PHP_ROUND_DOWN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (-3.5, 0, PHP_ROUND_UP)); +var_dump (round (-3.5, 0, PHP_ROUND_DOWN)); ?> --EXPECT-- float(3) float(2) float(2) float(3) +float(3) +float(2) float(-3) float(-2) float(-2) float(-3) +float(-2) +float(-3) +float(4) +float(3) float(4) float(3) float(4) @@ -36,3 +50,5 @@ float(-4) float(-3) float(-4) float(-3) +float(-3) +float(-4) From 220a45007920347fd577d76fd22fbd9b09ab2247 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Thu, 13 Jul 2023 23:35:20 +0200 Subject: [PATCH 02/20] Slight improvement for HALF_UP rounding --- ext/standard/math.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 3835c4c3aabcc..ac37b8e901f3f 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -98,7 +98,11 @@ static inline double php_round_helper(double value, int mode) { switch (mode) { case PHP_ROUND_HALF_UP: - tmp_value = round(value); + if (value >= 0.0) { + tmp_value = floor(value + 0.5); + } else { + tmp_value = ceil(value - 0.5); + } break; case PHP_ROUND_HALF_DOWN: if (value >= 0.0) { From e1967e81808d8cac28a330db2939414c8fc2440e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 14 Jul 2023 00:36:47 +0200 Subject: [PATCH 03/20] Refactor --- ext/standard/math.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index ac37b8e901f3f..92a4e00fdea6a 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -94,47 +94,39 @@ static inline double php_intpow10(int power) { /* {{{ php_round_helper Actually performs the rounding of a value to integer in a certain mode */ static inline double php_round_helper(double value, int mode) { - double tmp_value; - switch (mode) { case PHP_ROUND_HALF_UP: if (value >= 0.0) { - tmp_value = floor(value + 0.5); + return floor(value + 0.5); } else { - tmp_value = ceil(value - 0.5); + return ceil(value - 0.5); } break; case PHP_ROUND_HALF_DOWN: if (value >= 0.0) { - tmp_value = ceil(value - 0.5); + return ceil(value - 0.5); } else { - tmp_value = floor(value + 0.5); + return floor(value + 0.5); } - break; case PHP_ROUND_UP: - tmp_value = ceil(value); - break; + return ceil(value); case PHP_ROUND_DOWN: - tmp_value = floor(value); - break; + return floor(value); case PHP_ROUND_HALF_EVEN: - tmp_value = floor(value + 0.5); - if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { - tmp_value = tmp_value - 1.0; + double tmp_value_half_even = floor(value + 0.5); + if (tmp_value_half_even == value + 0.5 && fmod(tmp_value_half_even, 2.0) != 0.0) { + tmp_value_half_even = tmp_value_half_even - 1.0; } - break; + return tmp_value_half_even; case PHP_ROUND_HALF_ODD: - tmp_value = floor(value + 0.5); - if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { - tmp_value = tmp_value - 1.0; + double tmp_value_half_odd = floor(value + 0.5); + if (tmp_value_half_odd == value + 0.5 && fmod(tmp_value_half_odd, 2.0) == 0.0) { + tmp_value_half_odd = tmp_value_half_odd - 1.0; } - break; + return tmp_value_half_odd; default: - tmp_value = round(value); - break; + ZEND_ASSERT(0 && "Unexpected type"); } - - return tmp_value; } /* }}} */ From 526ec4173e8e83486937a5585d31b01a806f3d38 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 14 Jul 2023 01:05:01 +0200 Subject: [PATCH 04/20] Refactor --- ext/standard/math.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 92a4e00fdea6a..416b820324c28 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -94,39 +94,45 @@ static inline double php_intpow10(int power) { /* {{{ php_round_helper Actually performs the rounding of a value to integer in a certain mode */ static inline double php_round_helper(double value, int mode) { + double tmp_value; + switch (mode) { case PHP_ROUND_HALF_UP: if (value >= 0.0) { - return floor(value + 0.5); + tmp_value = floor(value + 0.5); } else { - return ceil(value - 0.5); + tmp_value= ceil(value - 0.5); } break; case PHP_ROUND_HALF_DOWN: if (value >= 0.0) { - return ceil(value - 0.5); + tmp_value = ceil(value - 0.5); } else { - return floor(value + 0.5); + tmp_value = floor(value + 0.5); } + break; case PHP_ROUND_UP: - return ceil(value); + tmp_value = ceil(value); + break; case PHP_ROUND_DOWN: - return floor(value); + tmp_value = floor(value); + break; case PHP_ROUND_HALF_EVEN: - double tmp_value_half_even = floor(value + 0.5); - if (tmp_value_half_even == value + 0.5 && fmod(tmp_value_half_even, 2.0) != 0.0) { - tmp_value_half_even = tmp_value_half_even - 1.0; + tmp_value = floor(value + 0.5); + if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { + tmp_value = tmp_value - 1.0; } - return tmp_value_half_even; + break; case PHP_ROUND_HALF_ODD: - double tmp_value_half_odd = floor(value + 0.5); - if (tmp_value_half_odd == value + 0.5 && fmod(tmp_value_half_odd, 2.0) == 0.0) { - tmp_value_half_odd = tmp_value_half_odd - 1.0; + tmp_value = floor(value + 0.5); + if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { + tmp_value = tmp_value - 1.0; } - return tmp_value_half_odd; + break; default: ZEND_ASSERT(0 && "Unexpected type"); } + return tmp_value; } /* }}} */ From e18af6c5d1c92237febf955535fcfa7f9cc0c41e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Tue, 18 Jul 2023 20:09:00 +0200 Subject: [PATCH 05/20] optimize calculation for half-even and half-odd --- ext/standard/math.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 416b820324c28..34fa17e17b9ae 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -119,13 +119,13 @@ static inline double php_round_helper(double value, int mode) { break; case PHP_ROUND_HALF_EVEN: tmp_value = floor(value + 0.5); - if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { + if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value/2.0))) { tmp_value = tmp_value - 1.0; } break; case PHP_ROUND_HALF_ODD: tmp_value = floor(value + 0.5); - if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { + if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)) { tmp_value = tmp_value - 1.0; } break; From e26bb3461dd0c8142fe81212b06d0bb2d6036d7a Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Tue, 18 Jul 2023 20:27:31 +0200 Subject: [PATCH 06/20] Update UPGRADING doc with changes to rounding modes for round function --- UPGRADING | 1 + ext/standard/basic_functions_arginfo.h | 31 ++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/UPGRADING b/UPGRADING index 56af1f0c1d419..6568e5f5efc9d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -297,6 +297,7 @@ PHP 8.3 UPGRADE NOTES means that when $decimals is negative, $num is rounded to $decimals significant digits before the decimal point. Previously negative $decimals got silently ignored and the number got rounded to zero decimal places. + . round() accepts two new rounding flags PHP_ROUND_UP and PHP_ROUND_DOWN. ======================================== 6. New Functions diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index c1d2c4302033a..7a3f96ea6e684 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: b7c035384e0a8dcd15bee4879277c14b46ddd6e9 */ + * Stub hash: decfa1e3d862d81880ea18150e2ba239bf15b8af */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -872,6 +872,10 @@ ZEND_END_ARG_INFO() #define arginfo_strtolower arginfo_base64_encode +#define arginfo_str_increment arginfo_base64_encode + +#define arginfo_str_decrement arginfo_base64_encode + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_basename, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, suffix, IS_STRING, 0, "\"\"") @@ -1845,6 +1849,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_context_set_option, 0, 2, ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_context_set_options, 0, 2, _IS_BOOL, 0) + ZEND_ARG_INFO(0, context) + ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stream_context_get_options, 0, 1, IS_ARRAY, 0) ZEND_ARG_INFO(0, stream_or_context) ZEND_END_ARG_INFO() @@ -2447,6 +2456,8 @@ ZEND_FUNCTION(implode); ZEND_FUNCTION(strtok); ZEND_FUNCTION(strtoupper); ZEND_FUNCTION(strtolower); +ZEND_FUNCTION(str_increment); +ZEND_FUNCTION(str_decrement); ZEND_FUNCTION(basename); ZEND_FUNCTION(dirname); ZEND_FUNCTION(pathinfo); @@ -2712,6 +2723,7 @@ ZEND_FUNCTION(stream_context_create); ZEND_FUNCTION(stream_context_set_params); ZEND_FUNCTION(stream_context_get_params); ZEND_FUNCTION(stream_context_set_option); +ZEND_FUNCTION(stream_context_set_options); ZEND_FUNCTION(stream_context_get_options); ZEND_FUNCTION(stream_context_get_default); ZEND_FUNCTION(stream_context_set_default); @@ -3061,7 +3073,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(htmlentities, arginfo_htmlentities) ZEND_FE(get_html_translation_table, arginfo_get_html_translation_table) ZEND_FE(assert, arginfo_assert) - ZEND_FE(assert_options, arginfo_assert_options) + ZEND_DEP_FE(assert_options, arginfo_assert_options) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(bin2hex, arginfo_bin2hex) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(hex2bin, arginfo_hex2bin) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strspn, arginfo_strspn) @@ -3081,6 +3093,8 @@ static const zend_function_entry ext_functions[] = { ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtok, arginfo_strtok) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtoupper, arginfo_strtoupper) ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtolower, arginfo_strtolower) + ZEND_FE(str_increment, arginfo_str_increment) + ZEND_FE(str_decrement, arginfo_str_decrement) ZEND_FE(basename, arginfo_basename) ZEND_FE(dirname, arginfo_dirname) ZEND_FE(pathinfo, arginfo_pathinfo) @@ -3350,6 +3364,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(stream_context_set_params, arginfo_stream_context_set_params) ZEND_FE(stream_context_get_params, arginfo_stream_context_get_params) ZEND_FE(stream_context_set_option, arginfo_stream_context_set_option) + ZEND_FE(stream_context_set_options, arginfo_stream_context_set_options) ZEND_FE(stream_context_get_options, arginfo_stream_context_get_options) ZEND_FE(stream_context_get_default, arginfo_stream_context_get_default) ZEND_FE(stream_context_set_default, arginfo_stream_context_set_default) @@ -3500,11 +3515,11 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", PHP_COUNT_RECURSIVE, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_BOTH", ARRAY_FILTER_USE_BOTH, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("ARRAY_FILTER_USE_KEY", ARRAY_FILTER_USE_KEY, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ASSERT_ACTIVE", PHP_ASSERT_ACTIVE, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ASSERT_CALLBACK", PHP_ASSERT_CALLBACK, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ASSERT_BAIL", PHP_ASSERT_BAIL, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ASSERT_WARNING", PHP_ASSERT_WARNING, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("ASSERT_EXCEPTION", PHP_ASSERT_EXCEPTION, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("ASSERT_ACTIVE", PHP_ASSERT_ACTIVE, CONST_PERSISTENT | CONST_DEPRECATED); + REGISTER_LONG_CONSTANT("ASSERT_CALLBACK", PHP_ASSERT_CALLBACK, CONST_PERSISTENT | CONST_DEPRECATED); + REGISTER_LONG_CONSTANT("ASSERT_BAIL", PHP_ASSERT_BAIL, CONST_PERSISTENT | CONST_DEPRECATED); + REGISTER_LONG_CONSTANT("ASSERT_WARNING", PHP_ASSERT_WARNING, CONST_PERSISTENT | CONST_DEPRECATED); + REGISTER_LONG_CONSTANT("ASSERT_EXCEPTION", PHP_ASSERT_EXCEPTION, CONST_PERSISTENT | CONST_DEPRECATED); REGISTER_LONG_CONSTANT("CONNECTION_ABORTED", PHP_CONNECTION_ABORTED, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CONNECTION_NORMAL", PHP_CONNECTION_NORMAL, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CONNECTION_TIMEOUT", PHP_CONNECTION_TIMEOUT, CONST_PERSISTENT); @@ -3565,6 +3580,8 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_UP", PHP_ROUND_UP, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_DOWN", PHP_ROUND_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); From 961cb3977f2cc48036771a8eb00a43ea4a0c8f1e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Tue, 18 Jul 2023 22:11:54 +0200 Subject: [PATCH 07/20] Generated stub for basic_functions_arginfo.h --- ext/standard/basic_functions_arginfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 7a3f96ea6e684..e706509bb1722 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: decfa1e3d862d81880ea18150e2ba239bf15b8af */ + * Stub hash: c52a5a3fb7b22f324fa070cf999b53bf708f58bc */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) From 9523c7dd95d368dc47422084c27934238ab125d7 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 21 Jul 2023 23:41:43 +0200 Subject: [PATCH 08/20] Added modes PHP_ROUND_TOWARD_ZERO and PHP_ROUND_AWAY_FROM_ZERO to round() --- NEWS | 1 + UPGRADING | 1 - ext/standard/basic_functions.stub.php | 18 ++++++++++--- ext/standard/basic_functions_arginfo.h | 8 +++--- ext/standard/math.c | 18 +++++++++++-- ext/standard/php_math.h | 16 +++++++++--- ext/standard/tests/math/round_modes.phpt | 32 ++++++++++++++++++------ 7 files changed, 72 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 153cb583e9cec..020df35d3fe91 100644 --- a/NEWS +++ b/NEWS @@ -75,6 +75,7 @@ PHP NEWS (Marc Bennewitz) . Added usage of posix_spawn for proc_open when supported by OS. (Cristian Rodriguez) + . Added 4 new rounding modes to the round(). (Jorg Sowa) - Streams: . Implemented GH-11242 (_php_stream_copy_to_mem: Allow specifying a maximum diff --git a/UPGRADING b/UPGRADING index 6568e5f5efc9d..56af1f0c1d419 100644 --- a/UPGRADING +++ b/UPGRADING @@ -297,7 +297,6 @@ PHP 8.3 UPGRADE NOTES means that when $decimals is negative, $num is rounded to $decimals significant digits before the decimal point. Previously negative $decimals got silently ignored and the number got rounded to zero decimal places. - . round() accepts two new rounding flags PHP_ROUND_UP and PHP_ROUND_DOWN. ======================================== 6. New Functions diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index ec3b67f1e1ebe..273fb7f92b82b 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -377,14 +377,24 @@ const PHP_ROUND_HALF_ODD = UNKNOWN; /** * @var int - * @cvalue PHP_ROUND_UP + * @cvalue PHP_ROUND_CEILING */ -const PHP_ROUND_UP = UNKNOWN; +const PHP_ROUND_CEILING = UNKNOWN; /** * @var int - * @cvalue PHP_ROUND_DOWN + * @cvalue PHP_ROUND_FLOOR */ -const PHP_ROUND_DOWN = UNKNOWN; +const PHP_ROUND_FLOOR = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_TOWARD_ZERO + */ +const PHP_ROUND_TOWARD_ZERO = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_AWAY_FROM_ZERO + */ +const PHP_ROUND_AWAY_FROM_ZERO = UNKNOWN; /* crypt.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index e706509bb1722..564d4bd489f96 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c52a5a3fb7b22f324fa070cf999b53bf708f58bc */ + * Stub hash: c4adf194a2c72b6c4618e7c3e9f07ef143ad9d20 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -3580,8 +3580,10 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_UP", PHP_ROUND_UP, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_DOWN", PHP_ROUND_DOWN, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_CEILING", PHP_ROUND_CEILING, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_FLOOR", PHP_ROUND_FLOOR, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_TOWARD_ZERO", PHP_ROUND_TOWARD_ZERO, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_AWAY_FROM_ZERO", PHP_ROUND_AWAY_FROM_ZERO, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); diff --git a/ext/standard/math.c b/ext/standard/math.c index 031513dca2671..0c428c14ea99d 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -110,12 +110,26 @@ static inline double php_round_helper(double value, int mode) { tmp_value = floor(value + 0.5); } break; - case PHP_ROUND_UP: + case PHP_ROUND_CEILING: tmp_value = ceil(value); break; - case PHP_ROUND_DOWN: + case PHP_ROUND_FLOOR: tmp_value = floor(value); break; + case PHP_ROUND_TOWARD_ZERO: + if(value >= 0.0) { + tmp_value = floor(value); + } else { + tmp_value = ceil(value); + } + break; + case PHP_ROUND_AWAY_FROM_ZERO: + if(value >= 0.0) { + tmp_value = ceil(value); + } else { + tmp_value = floor(value); + } + break; case PHP_ROUND_HALF_EVEN: tmp_value = floor(value + 0.5); if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value/2.0))) { diff --git a/ext/standard/php_math.h b/ext/standard/php_math.h index a3133b9c26598..ff0df61ef0d50 100644 --- a/ext/standard/php_math.h +++ b/ext/standard/php_math.h @@ -114,12 +114,20 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base); #define PHP_ROUND_HALF_ODD 0x04 #endif -#ifndef PHP_ROUND_UP -#define PHP_ROUND_UP 0x05 +#ifndef PHP_ROUND_CEILING +#define PHP_ROUND_CEILING 0x05 #endif -#ifndef PHP_ROUND_DOWN -#define PHP_ROUND_DOWN 0x06 +#ifndef PHP_ROUND_FLOOR +#define PHP_ROUND_FLOOR 0x06 +#endif + +#ifndef PHP_ROUND_TOWARD_ZERO +#define PHP_ROUND_TOWARD_ZERO 0x07 +#endif + +#ifndef PHP_ROUND_AWAY_FROM_ZERO +#define PHP_ROUND_AWAY_FROM_ZERO 0x08 #endif #endif /* PHP_MATH_H */ diff --git a/ext/standard/tests/math/round_modes.phpt b/ext/standard/tests/math/round_modes.phpt index f6cbdaf78d515..5a3b410cac903 100644 --- a/ext/standard/tests/math/round_modes.phpt +++ b/ext/standard/tests/math/round_modes.phpt @@ -6,26 +6,34 @@ var_dump (round (2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (2.5, 0, PHP_ROUND_UP)); -var_dump (round (2.5, 0, PHP_ROUND_DOWN)); +var_dump (round (2.5, 0, PHP_ROUND_CEILING)); +var_dump (round (2.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (2.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (2.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (-2.5, 0, PHP_ROUND_UP)); -var_dump (round (-2.5, 0, PHP_ROUND_DOWN)); +var_dump (round (-2.5, 0, PHP_ROUND_CEILING)); +var_dump (round (-2.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (-2.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (-2.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); var_dump (round (3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (3.5, 0, PHP_ROUND_UP)); -var_dump (round (3.5, 0, PHP_ROUND_DOWN)); +var_dump (round (3.5, 0, PHP_ROUND_CEILING)); +var_dump (round (3.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (3.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (3.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (-3.5, 0, PHP_ROUND_UP)); -var_dump (round (-3.5, 0, PHP_ROUND_DOWN)); +var_dump (round (-3.5, 0, PHP_ROUND_CEILING)); +var_dump (round (-3.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (-3.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (-3.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); ?> --EXPECT-- float(3) @@ -34,21 +42,29 @@ float(2) float(3) float(3) float(2) +float(2) +float(3) float(-3) float(-2) float(-2) float(-3) float(-2) float(-3) +float(-2) +float(-3) float(4) float(3) float(4) float(3) float(4) float(3) +float(3) +float(4) float(-4) float(-3) float(-4) float(-3) float(-3) float(-4) +float(-3) +float(-4) From 4c43ba9b05692399a186509b3031513bf7e0645e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Thu, 13 Jul 2023 22:43:53 +0200 Subject: [PATCH 09/20] Introduce two new modes to round function --- ext/standard/basic_functions.stub.php | 10 +++++ ext/standard/math.c | 48 ++++++++++++++++-------- ext/standard/php_math.h | 8 ++++ ext/standard/tests/math/round_modes.phpt | 16 ++++++++ 4 files changed, 66 insertions(+), 16 deletions(-) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 6fed9c8064a38..ec3b67f1e1ebe 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -375,6 +375,16 @@ * @cvalue PHP_ROUND_HALF_ODD */ const PHP_ROUND_HALF_ODD = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_UP + */ +const PHP_ROUND_UP = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_DOWN + */ +const PHP_ROUND_DOWN = UNKNOWN; /* crypt.c */ diff --git a/ext/standard/math.c b/ext/standard/math.c index 74ffa565031a3..eabb3ed125857 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -95,22 +95,38 @@ static inline double php_intpow10(int power) { static inline double php_round_helper(double value, int mode) { double tmp_value; - if (value >= 0.0) { - tmp_value = floor(value + 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0))) - { - tmp_value = tmp_value - 1.0; - } - } else { - tmp_value = ceil(value - 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0))) - { - tmp_value = tmp_value + 1.0; - } + switch (mode) { + case PHP_ROUND_HALF_UP: + tmp_value = round(value); + break; + case PHP_ROUND_HALF_DOWN: + if (value >= 0.0) { + tmp_value = ceil(value - 0.5); + } else { + tmp_value = floor(value + 0.5); + } + break; + case PHP_ROUND_UP: + tmp_value = ceil(value); + break; + case PHP_ROUND_DOWN: + tmp_value = floor(value); + break; + case PHP_ROUND_HALF_EVEN: + tmp_value = floor(value + 0.5); + if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { + tmp_value = tmp_value - 1.0; + } + break; + case PHP_ROUND_HALF_ODD: + tmp_value = floor(value + 0.5); + if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { + tmp_value = tmp_value - 1.0; + } + break; + default: + tmp_value = round(value); + break; } return tmp_value; diff --git a/ext/standard/php_math.h b/ext/standard/php_math.h index 1cdba0fe9d0a6..a3133b9c26598 100644 --- a/ext/standard/php_math.h +++ b/ext/standard/php_math.h @@ -114,4 +114,12 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base); #define PHP_ROUND_HALF_ODD 0x04 #endif +#ifndef PHP_ROUND_UP +#define PHP_ROUND_UP 0x05 +#endif + +#ifndef PHP_ROUND_DOWN +#define PHP_ROUND_DOWN 0x06 +#endif + #endif /* PHP_MATH_H */ diff --git a/ext/standard/tests/math/round_modes.phpt b/ext/standard/tests/math/round_modes.phpt index 03479c4d908fe..f6cbdaf78d515 100644 --- a/ext/standard/tests/math/round_modes.phpt +++ b/ext/standard/tests/math/round_modes.phpt @@ -6,28 +6,42 @@ var_dump (round (2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (2.5, 0, PHP_ROUND_UP)); +var_dump (round (2.5, 0, PHP_ROUND_DOWN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (-2.5, 0, PHP_ROUND_UP)); +var_dump (round (-2.5, 0, PHP_ROUND_DOWN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (3.5, 0, PHP_ROUND_UP)); +var_dump (round (3.5, 0, PHP_ROUND_DOWN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_ODD)); +var_dump (round (-3.5, 0, PHP_ROUND_UP)); +var_dump (round (-3.5, 0, PHP_ROUND_DOWN)); ?> --EXPECT-- float(3) float(2) float(2) float(3) +float(3) +float(2) float(-3) float(-2) float(-2) float(-3) +float(-2) +float(-3) +float(4) +float(3) float(4) float(3) float(4) @@ -36,3 +50,5 @@ float(-4) float(-3) float(-4) float(-3) +float(-3) +float(-4) From c960b0dc8f02de29f73699d6bc524ed04c59c0d0 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Thu, 13 Jul 2023 23:35:20 +0200 Subject: [PATCH 10/20] Slight improvement for HALF_UP rounding --- ext/standard/math.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index eabb3ed125857..c4bef2952dbe2 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -97,7 +97,11 @@ static inline double php_round_helper(double value, int mode) { switch (mode) { case PHP_ROUND_HALF_UP: - tmp_value = round(value); + if (value >= 0.0) { + tmp_value = floor(value + 0.5); + } else { + tmp_value = ceil(value - 0.5); + } break; case PHP_ROUND_HALF_DOWN: if (value >= 0.0) { From 027e3e6c09f781e3c66d3cdfcee2235c6be325da Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 14 Jul 2023 00:36:47 +0200 Subject: [PATCH 11/20] Refactor --- ext/standard/math.c | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index c4bef2952dbe2..38aded62b33f0 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -93,47 +93,39 @@ static inline double php_intpow10(int power) { /* {{{ php_round_helper Actually performs the rounding of a value to integer in a certain mode */ static inline double php_round_helper(double value, int mode) { - double tmp_value; - switch (mode) { case PHP_ROUND_HALF_UP: if (value >= 0.0) { - tmp_value = floor(value + 0.5); + return floor(value + 0.5); } else { - tmp_value = ceil(value - 0.5); + return ceil(value - 0.5); } break; case PHP_ROUND_HALF_DOWN: if (value >= 0.0) { - tmp_value = ceil(value - 0.5); + return ceil(value - 0.5); } else { - tmp_value = floor(value + 0.5); + return floor(value + 0.5); } - break; case PHP_ROUND_UP: - tmp_value = ceil(value); - break; + return ceil(value); case PHP_ROUND_DOWN: - tmp_value = floor(value); - break; + return floor(value); case PHP_ROUND_HALF_EVEN: - tmp_value = floor(value + 0.5); - if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { - tmp_value = tmp_value - 1.0; + double tmp_value_half_even = floor(value + 0.5); + if (tmp_value_half_even == value + 0.5 && fmod(tmp_value_half_even, 2.0) != 0.0) { + tmp_value_half_even = tmp_value_half_even - 1.0; } - break; + return tmp_value_half_even; case PHP_ROUND_HALF_ODD: - tmp_value = floor(value + 0.5); - if(tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { - tmp_value = tmp_value - 1.0; + double tmp_value_half_odd = floor(value + 0.5); + if (tmp_value_half_odd == value + 0.5 && fmod(tmp_value_half_odd, 2.0) == 0.0) { + tmp_value_half_odd = tmp_value_half_odd - 1.0; } - break; + return tmp_value_half_odd; default: - tmp_value = round(value); - break; + ZEND_ASSERT(0 && "Unexpected type"); } - - return tmp_value; } /* }}} */ From 2a91eb55b8eb9c3c9fc83dce8edc44e7b9f490fa Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 14 Jul 2023 01:05:01 +0200 Subject: [PATCH 12/20] Refactor --- ext/standard/math.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 38aded62b33f0..cc131b436ab00 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -93,39 +93,45 @@ static inline double php_intpow10(int power) { /* {{{ php_round_helper Actually performs the rounding of a value to integer in a certain mode */ static inline double php_round_helper(double value, int mode) { + double tmp_value; + switch (mode) { case PHP_ROUND_HALF_UP: if (value >= 0.0) { - return floor(value + 0.5); + tmp_value = floor(value + 0.5); } else { - return ceil(value - 0.5); + tmp_value= ceil(value - 0.5); } break; case PHP_ROUND_HALF_DOWN: if (value >= 0.0) { - return ceil(value - 0.5); + tmp_value = ceil(value - 0.5); } else { - return floor(value + 0.5); + tmp_value = floor(value + 0.5); } + break; case PHP_ROUND_UP: - return ceil(value); + tmp_value = ceil(value); + break; case PHP_ROUND_DOWN: - return floor(value); + tmp_value = floor(value); + break; case PHP_ROUND_HALF_EVEN: - double tmp_value_half_even = floor(value + 0.5); - if (tmp_value_half_even == value + 0.5 && fmod(tmp_value_half_even, 2.0) != 0.0) { - tmp_value_half_even = tmp_value_half_even - 1.0; + tmp_value = floor(value + 0.5); + if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { + tmp_value = tmp_value - 1.0; } - return tmp_value_half_even; + break; case PHP_ROUND_HALF_ODD: - double tmp_value_half_odd = floor(value + 0.5); - if (tmp_value_half_odd == value + 0.5 && fmod(tmp_value_half_odd, 2.0) == 0.0) { - tmp_value_half_odd = tmp_value_half_odd - 1.0; + tmp_value = floor(value + 0.5); + if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { + tmp_value = tmp_value - 1.0; } - return tmp_value_half_odd; + break; default: ZEND_ASSERT(0 && "Unexpected type"); } + return tmp_value; } /* }}} */ From 3cf6a3219f9ba26d4519be5877ebdb0ed0b4ae8f Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Tue, 18 Jul 2023 20:09:00 +0200 Subject: [PATCH 13/20] optimize calculation for half-even and half-odd --- ext/standard/math.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index cc131b436ab00..ac6319bc3cbec 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -118,13 +118,13 @@ static inline double php_round_helper(double value, int mode) { break; case PHP_ROUND_HALF_EVEN: tmp_value = floor(value + 0.5); - if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) != 0.0) { + if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value/2.0))) { tmp_value = tmp_value - 1.0; } break; case PHP_ROUND_HALF_ODD: tmp_value = floor(value + 0.5); - if (tmp_value == value + 0.5 && fmod(tmp_value, 2.0) == 0.0) { + if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)) { tmp_value = tmp_value - 1.0; } break; From 71dbbc3e92cda942a9ff5084d508d14ac5cbbcba Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Tue, 18 Jul 2023 20:27:31 +0200 Subject: [PATCH 14/20] Update UPGRADING doc with changes to rounding modes for round function --- UPGRADING | 1 + ext/standard/basic_functions_arginfo.h | 2 ++ 2 files changed, 3 insertions(+) diff --git a/UPGRADING b/UPGRADING index 156039af1c72a..72b856bc6bc77 100644 --- a/UPGRADING +++ b/UPGRADING @@ -345,6 +345,7 @@ PHP 8.3 UPGRADE NOTES means that when $decimals is negative, $num is rounded to $decimals significant digits before the decimal point. Previously negative $decimals got silently ignored and the number got rounded to zero decimal places. + . round() accepts two new rounding flags PHP_ROUND_UP and PHP_ROUND_DOWN. ======================================== 6. New Functions diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index f325634e95cc1..7a3f96ea6e684 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -3580,6 +3580,8 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_UP", PHP_ROUND_UP, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_DOWN", PHP_ROUND_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); From f6c908d3e815f1c3b2899084d30dbdc29e9d6984 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Tue, 18 Jul 2023 22:11:54 +0200 Subject: [PATCH 15/20] Generated stub for basic_functions_arginfo.h --- ext/standard/basic_functions_arginfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 7a3f96ea6e684..e706509bb1722 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: decfa1e3d862d81880ea18150e2ba239bf15b8af */ + * Stub hash: c52a5a3fb7b22f324fa070cf999b53bf708f58bc */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) From f3ff32c66db010d02bc4a51940f1ba7672dbe7c4 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 21 Jul 2023 23:41:43 +0200 Subject: [PATCH 16/20] Added modes PHP_ROUND_TOWARD_ZERO and PHP_ROUND_AWAY_FROM_ZERO to round() --- NEWS | 1 + UPGRADING | 1 - ext/standard/basic_functions.stub.php | 18 ++++++++++--- ext/standard/basic_functions_arginfo.h | 8 +++--- ext/standard/math.c | 18 +++++++++++-- ext/standard/php_math.h | 16 +++++++++--- ext/standard/tests/math/round_modes.phpt | 32 ++++++++++++++++++------ 7 files changed, 72 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 1fc291a33a4bf..439a9320340ad 100644 --- a/NEWS +++ b/NEWS @@ -146,6 +146,7 @@ PHP NEWS (Marc Bennewitz) . Added usage of posix_spawn for proc_open when supported by OS. (Cristian Rodriguez) + . Added 4 new rounding modes to the round(). (Jorg Sowa) - Streams: . Implemented GH-11242 (_php_stream_copy_to_mem: Allow specifying a maximum diff --git a/UPGRADING b/UPGRADING index 72b856bc6bc77..156039af1c72a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -345,7 +345,6 @@ PHP 8.3 UPGRADE NOTES means that when $decimals is negative, $num is rounded to $decimals significant digits before the decimal point. Previously negative $decimals got silently ignored and the number got rounded to zero decimal places. - . round() accepts two new rounding flags PHP_ROUND_UP and PHP_ROUND_DOWN. ======================================== 6. New Functions diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index ec3b67f1e1ebe..273fb7f92b82b 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -377,14 +377,24 @@ const PHP_ROUND_HALF_ODD = UNKNOWN; /** * @var int - * @cvalue PHP_ROUND_UP + * @cvalue PHP_ROUND_CEILING */ -const PHP_ROUND_UP = UNKNOWN; +const PHP_ROUND_CEILING = UNKNOWN; /** * @var int - * @cvalue PHP_ROUND_DOWN + * @cvalue PHP_ROUND_FLOOR */ -const PHP_ROUND_DOWN = UNKNOWN; +const PHP_ROUND_FLOOR = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_TOWARD_ZERO + */ +const PHP_ROUND_TOWARD_ZERO = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_AWAY_FROM_ZERO + */ +const PHP_ROUND_AWAY_FROM_ZERO = UNKNOWN; /* crypt.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index e706509bb1722..564d4bd489f96 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c52a5a3fb7b22f324fa070cf999b53bf708f58bc */ + * Stub hash: c4adf194a2c72b6c4618e7c3e9f07ef143ad9d20 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -3580,8 +3580,10 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_UP", PHP_ROUND_UP, CONST_PERSISTENT); - REGISTER_LONG_CONSTANT("PHP_ROUND_DOWN", PHP_ROUND_DOWN, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_CEILING", PHP_ROUND_CEILING, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_FLOOR", PHP_ROUND_FLOOR, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_TOWARD_ZERO", PHP_ROUND_TOWARD_ZERO, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_AWAY_FROM_ZERO", PHP_ROUND_AWAY_FROM_ZERO, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); diff --git a/ext/standard/math.c b/ext/standard/math.c index ac6319bc3cbec..8f62aafef10b7 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -110,12 +110,26 @@ static inline double php_round_helper(double value, int mode) { tmp_value = floor(value + 0.5); } break; - case PHP_ROUND_UP: + case PHP_ROUND_CEILING: tmp_value = ceil(value); break; - case PHP_ROUND_DOWN: + case PHP_ROUND_FLOOR: tmp_value = floor(value); break; + case PHP_ROUND_TOWARD_ZERO: + if(value >= 0.0) { + tmp_value = floor(value); + } else { + tmp_value = ceil(value); + } + break; + case PHP_ROUND_AWAY_FROM_ZERO: + if(value >= 0.0) { + tmp_value = ceil(value); + } else { + tmp_value = floor(value); + } + break; case PHP_ROUND_HALF_EVEN: tmp_value = floor(value + 0.5); if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value/2.0))) { diff --git a/ext/standard/php_math.h b/ext/standard/php_math.h index a3133b9c26598..ff0df61ef0d50 100644 --- a/ext/standard/php_math.h +++ b/ext/standard/php_math.h @@ -114,12 +114,20 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base); #define PHP_ROUND_HALF_ODD 0x04 #endif -#ifndef PHP_ROUND_UP -#define PHP_ROUND_UP 0x05 +#ifndef PHP_ROUND_CEILING +#define PHP_ROUND_CEILING 0x05 #endif -#ifndef PHP_ROUND_DOWN -#define PHP_ROUND_DOWN 0x06 +#ifndef PHP_ROUND_FLOOR +#define PHP_ROUND_FLOOR 0x06 +#endif + +#ifndef PHP_ROUND_TOWARD_ZERO +#define PHP_ROUND_TOWARD_ZERO 0x07 +#endif + +#ifndef PHP_ROUND_AWAY_FROM_ZERO +#define PHP_ROUND_AWAY_FROM_ZERO 0x08 #endif #endif /* PHP_MATH_H */ diff --git a/ext/standard/tests/math/round_modes.phpt b/ext/standard/tests/math/round_modes.phpt index f6cbdaf78d515..5a3b410cac903 100644 --- a/ext/standard/tests/math/round_modes.phpt +++ b/ext/standard/tests/math/round_modes.phpt @@ -6,26 +6,34 @@ var_dump (round (2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (2.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (2.5, 0, PHP_ROUND_UP)); -var_dump (round (2.5, 0, PHP_ROUND_DOWN)); +var_dump (round (2.5, 0, PHP_ROUND_CEILING)); +var_dump (round (2.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (2.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (2.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-2.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (-2.5, 0, PHP_ROUND_UP)); -var_dump (round (-2.5, 0, PHP_ROUND_DOWN)); +var_dump (round (-2.5, 0, PHP_ROUND_CEILING)); +var_dump (round (-2.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (-2.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (-2.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); var_dump (round (3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (3.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (3.5, 0, PHP_ROUND_UP)); -var_dump (round (3.5, 0, PHP_ROUND_DOWN)); +var_dump (round (3.5, 0, PHP_ROUND_CEILING)); +var_dump (round (3.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (3.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (3.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_UP)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_DOWN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_EVEN)); var_dump (round (-3.5, 0, PHP_ROUND_HALF_ODD)); -var_dump (round (-3.5, 0, PHP_ROUND_UP)); -var_dump (round (-3.5, 0, PHP_ROUND_DOWN)); +var_dump (round (-3.5, 0, PHP_ROUND_CEILING)); +var_dump (round (-3.5, 0, PHP_ROUND_FLOOR)); +var_dump (round (-3.5, 0, PHP_ROUND_TOWARD_ZERO)); +var_dump (round (-3.5, 0, PHP_ROUND_AWAY_FROM_ZERO)); ?> --EXPECT-- float(3) @@ -34,21 +42,29 @@ float(2) float(3) float(3) float(2) +float(2) +float(3) float(-3) float(-2) float(-2) float(-3) float(-2) float(-3) +float(-2) +float(-3) float(4) float(3) float(4) float(3) float(4) float(3) +float(3) +float(4) float(-4) float(-3) float(-4) float(-3) float(-3) float(-4) +float(-3) +float(-4) From 01356f564857443638e714992136d016cda54e5e Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Fri, 25 Aug 2023 00:32:47 +0200 Subject: [PATCH 17/20] Generate stub --- ext/standard/basic_functions_arginfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 1fa16876ea002..b71aea1fb78bd 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: c4adf194a2c72b6c4618e7c3e9f07ef143ad9d20 */ + * Stub hash: 8685bba87eaaa085e2be8b9f00bbb35c58e93797 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) From 383be5dbff9a5cd4044826219d7dffd865e5f079 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Wed, 23 Aug 2023 13:19:13 +0100 Subject: [PATCH 18/20] [skip ci] Mark test as XLEAK due to LSAN bug (#12018) This is due to apparently some combination of glibc and Clang 14 which we are unfortunately hitting --- sapi/cli/tests/ext_loading.phpt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sapi/cli/tests/ext_loading.phpt b/sapi/cli/tests/ext_loading.phpt index 1769f1f657555..f262b3e2ac3f7 100644 --- a/sapi/cli/tests/ext_loading.phpt +++ b/sapi/cli/tests/ext_loading.phpt @@ -2,6 +2,9 @@ Extension loading --SKIPIF-- Date: Wed, 23 Aug 2023 12:58:32 +0200 Subject: [PATCH 19/20] Switch asan build to Ubuntu 23.04 in Docker Closes GH-12034 --- sapi/cli/tests/ext_loading.phpt | 3 --- 1 file changed, 3 deletions(-) diff --git a/sapi/cli/tests/ext_loading.phpt b/sapi/cli/tests/ext_loading.phpt index f262b3e2ac3f7..1769f1f657555 100644 --- a/sapi/cli/tests/ext_loading.phpt +++ b/sapi/cli/tests/ext_loading.phpt @@ -2,9 +2,6 @@ Extension loading --SKIPIF-- Date: Fri, 25 Aug 2023 00:27:55 +0200 Subject: [PATCH 20/20] Implement 4 new rounding modes to round() --- NEWS | 3 + ext/standard/basic_functions.stub.php | 20 ++ ext/standard/basic_functions_arginfo.h | 6 +- ext/standard/math.c | 66 ++++-- ext/standard/php_math.h | 18 +- ext/standard/tests/math/round_modes.phpt | 248 +++++++++++++++++++++++ 6 files changed, 342 insertions(+), 19 deletions(-) diff --git a/NEWS b/NEWS index 33a9713ade2aa..0be2015d41eb8 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,9 @@ PHP NEWS - Standard: . Added $before_needle argument to strrchr(). (HypeMC) +- Standard: + . Added 4 new rounding modes to the round(). (Jorg Sowa) + 17 Aug 2023, PHP 8.3.0beta3 - Core: diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 66b458897adb4..8acda24291f2e 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -375,6 +375,26 @@ * @cvalue PHP_ROUND_HALF_ODD */ const PHP_ROUND_HALF_ODD = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_CEILING + */ +const PHP_ROUND_CEILING = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_FLOOR + */ +const PHP_ROUND_FLOOR = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_TOWARD_ZERO + */ +const PHP_ROUND_TOWARD_ZERO = UNKNOWN; +/** + * @var int + * @cvalue PHP_ROUND_AWAY_FROM_ZERO + */ +const PHP_ROUND_AWAY_FROM_ZERO = UNKNOWN; /* crypt.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index 36b9cb1b9dce6..b71aea1fb78bd 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 487cee0751d47b18bf0a8fbdb050313783f1b369 */ + * Stub hash: 8685bba87eaaa085e2be8b9f00bbb35c58e93797 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -3577,6 +3577,10 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_DOWN", PHP_ROUND_HALF_DOWN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_EVEN", PHP_ROUND_HALF_EVEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("PHP_ROUND_HALF_ODD", PHP_ROUND_HALF_ODD, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_CEILING", PHP_ROUND_CEILING, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_FLOOR", PHP_ROUND_FLOOR, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_TOWARD_ZERO", PHP_ROUND_TOWARD_ZERO, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("PHP_ROUND_AWAY_FROM_ZERO", PHP_ROUND_AWAY_FROM_ZERO, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SALT_LENGTH", PHP_MAX_SALT_LEN, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_STD_DES", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_EXT_DES", 1, CONST_PERSISTENT); diff --git a/ext/standard/math.c b/ext/standard/math.c index 74ffa565031a3..2d0b81fee3efd 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -95,24 +95,56 @@ static inline double php_intpow10(int power) { static inline double php_round_helper(double value, int mode) { double tmp_value; - if (value >= 0.0) { - tmp_value = floor(value + 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0))) - { - tmp_value = tmp_value - 1.0; - } - } else { - tmp_value = ceil(value - 0.5); - if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) || - (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) || - (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0))) - { - tmp_value = tmp_value + 1.0; - } + switch (mode) { + case PHP_ROUND_HALF_UP: + if (value >= 0.0) { + tmp_value = floor(value + 0.5); + } else { + tmp_value = ceil(value - 0.5); + } + break; + case PHP_ROUND_HALF_DOWN: + if (value >= 0.0) { + tmp_value = ceil(value - 0.5); + } else { + tmp_value = floor(value + 0.5); + } + break; + case PHP_ROUND_CEILING: + tmp_value = ceil(value); + break; + case PHP_ROUND_FLOOR: + tmp_value = floor(value); + break; + case PHP_ROUND_TOWARD_ZERO: + if(value >= 0.0) { + tmp_value = floor(value); + } else { + tmp_value = ceil(value); + } + break; + case PHP_ROUND_AWAY_FROM_ZERO: + if(value >= 0.0) { + tmp_value = ceil(value); + } else { + tmp_value = floor(value); + } + break; + case PHP_ROUND_HALF_EVEN: + tmp_value = floor(value + 0.5); + if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value / 2.0))) { + tmp_value = tmp_value - 1.0; + } + break; + case PHP_ROUND_HALF_ODD: + tmp_value = floor(value + 0.5); + if (tmp_value == value + 0.5 && value == (0.5 + 2 * floor(tmp_value / 2.0) - 1.0)) { + tmp_value = tmp_value - 1.0; + } + break; + default: + ZEND_ASSERT(0 && "Unexpected type"); } - return tmp_value; } /* }}} */ diff --git a/ext/standard/php_math.h b/ext/standard/php_math.h index 1cdba0fe9d0a6..6ff895cce3c8d 100644 --- a/ext/standard/php_math.h +++ b/ext/standard/php_math.h @@ -103,7 +103,7 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base); #endif #ifndef PHP_ROUND_HALF_DOWN -#define PHP_ROUND_HALF_DOWN 0x02 /* Down == towards zero */ +#define PHP_ROUND_HALF_DOWN 0x02 /* Arithmetic rounding, down == towards zero */ #endif #ifndef PHP_ROUND_HALF_EVEN @@ -114,4 +114,20 @@ PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base); #define PHP_ROUND_HALF_ODD 0x04 #endif +#ifndef PHP_ROUND_CEILING +#define PHP_ROUND_CEILING 0x05 +#endif + +#ifndef PHP_ROUND_FLOOR +#define PHP_ROUND_FLOOR 0x06 +#endif + +#ifndef PHP_ROUND_TOWARD_ZERO +#define PHP_ROUND_TOWARD_ZERO 0x07 +#endif + +#ifndef PHP_ROUND_AWAY_FROM_ZERO +#define PHP_ROUND_AWAY_FROM_ZERO 0x08 +#endif + #endif /* PHP_MATH_H */ diff --git a/ext/standard/tests/math/round_modes.phpt b/ext/standard/tests/math/round_modes.phpt index 23a0224efbca6..5c125473f8292 100644 --- a/ext/standard/tests/math/round_modes.phpt +++ b/ext/standard/tests/math/round_modes.phpt @@ -7,6 +7,10 @@ $modes = [ "PHP_ROUND_HALF_DOWN" => PHP_ROUND_HALF_DOWN, "PHP_ROUND_HALF_EVEN" => PHP_ROUND_HALF_EVEN, "PHP_ROUND_HALF_ODD" => PHP_ROUND_HALF_ODD, + "PHP_ROUND_CEILING" => PHP_ROUND_CEILING, + "PHP_ROUND_FLOOR" => PHP_ROUND_FLOOR, + "PHP_ROUND_TOWARD_ZERO" => PHP_ROUND_TOWARD_ZERO, + "PHP_ROUND_AWAY_FROM_ZERO" => PHP_ROUND_AWAY_FROM_ZERO, ]; $numbers = [ @@ -285,3 +289,247 @@ mode: PHP_ROUND_HALF_ODD -1.9999 => -1.9999 0.0001 => 0.0001 -0.0001 => -0.0001 + +mode: PHP_ROUND_CEILING + precision: 0 + 2.5 => 3 + -2.5 => -3 + 3.5 => 4 + -3.5 => -4 + 7 => 7 + -7 => -7 + 0.61 => 1 + 0.69 => 1 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 1 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.6 + 0.69 => 0.7 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 2 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 10 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 1.9999 + -1.9999 => -1.9999 + 0.0001 => 0.0001 + -0.0001 => -0.0001 + +mode: PHP_ROUND_FLOOR + precision: 0 + 2.5 => 3 + -2.5 => -3 + 3.5 => 4 + -3.5 => -4 + 7 => 7 + -7 => -7 + 0.61 => 1 + 0.69 => 1 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 1 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.6 + 0.69 => 0.7 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 2 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 10 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 1.9999 + -1.9999 => -1.9999 + 0.0001 => 0.0001 + -0.0001 => -0.0001 + +mode: PHP_ROUND_TOWARD_ZERO + precision: 0 + 2.5 => 3 + -2.5 => -3 + 3.5 => 4 + -3.5 => -4 + 7 => 7 + -7 => -7 + 0.61 => 1 + 0.69 => 1 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 1 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.6 + 0.69 => 0.7 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 2 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 10 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 1.9999 + -1.9999 => -1.9999 + 0.0001 => 0.0001 + -0.0001 => -0.0001 + +mode: PHP_ROUND_AWAY_FROM_ZERO + precision: 0 + 2.5 => 3 + -2.5 => -3 + 3.5 => 4 + -3.5 => -4 + 7 => 7 + -7 => -7 + 0.61 => 1 + 0.69 => 1 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 1 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.6 + 0.69 => 0.7 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 2 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 2 + -1.9999 => -2 + 0.0001 => 0 + -0.0001 => -0 + + precision: 10 + 2.5 => 2.5 + -2.5 => -2.5 + 3.5 => 3.5 + -3.5 => -3.5 + 7 => 7 + -7 => -7 + 0.61 => 0.61 + 0.69 => 0.69 + 0 => 0 + 1.9999 => 1.9999 + -1.9999 => -1.9999 + 0.0001 => 0.0001 + -0.0001 => -0.0001