diff --git a/NEWS b/NEWS index 33a9713ade2aa..cfee237a5534b 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: @@ -155,6 +158,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/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..8f62aafef10b7 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