Hello internals,

While reviewing the PR for the "Adding bcround, bcfloor and bcceil to BCMath" 
RFC [1] with the different rounding modes,
I was made aware of the unfortunate wrong terminology usage of 
PHP_ROUND_HALF_UP and PHP_ROUND_HALF_DOWN.

Indeed, PHP_ROUND_HALF_UP is implemented as "rounding half away from zero" and 
not "rounding half up" (which is also called rounding toward positive infinity).
The behaviour for positive numbers is the same, however for negative numbers 
the rounding *is* different.
In the same vein, PHP_ROUND_HALD_DOWN is implemented as "rounding half toward 
zero" and not "rounding half down" (/round half toward negative infinity).

Taking -1.5 as our number:
 - Rounding half-up: -1
 - Rounding half away from zero: -2
 - Rounding half-down: -2
 - Rounding half towards zero: -1

For a detailed explanation about rounding, the Wikipedia page is of great use. 
[2]
And the following rounding calculator on Calculator Soup is useful to check the 
differences and behaviour of different rounding modes. [3]

It should be noted that PHP is in good company about being wrong about those 
two rounding modes, Java, Python, and Ruby (and probably others) are also wrong 
in this regard.

Considering that PHP 8.4 is also adding new rounding modes via the "Add 4 new 
rounding modes to round() function" RFC [4] attempting to solve this issue in 
this next version of PHP seems like a good idea.
In my discussions with Saki about this issue, it seems that her and Tim have 
thought about creating a new enum for rounding modes, looking something like 
this:

enum RoundingMode {
    case HalfAwayFromZero;
    case HalfTowardsZero;
    case HalfEven;
    case HalfOdd;
    case TowardsZero;
    case AwayFromZero;
    case NegativeInfinity; // or case Floor;
    case PositiveInfinity; // or case Ceiling;
}

and change the signature of round from:
round(int|float $num, int $precision = 0, int $mode = PHP_ROUND_HALF_UP): float
to
round(int|float $num, int $precision = 0, RoundingMode $mode = 
RoundingMode::HalfAwayFromZero): float

and changing the definition of the existing constants to effectively be:
define('PHP_ROUND_HALF_UP', RoundingMode::HalfAwayFromZero);
define('PHP_ROUND_HALF_DOWN', RoundingMode::HalfTowardsZero);
define('PHP_ROUND_HALF_EVEN', RoundingMode::HalfEven);
define('PHP_ROUND_HALF_ODD', RoundingMode::HalfOdd);

This should not cause any BC breaks, while allowing us to potentially implement 
the half up/down rounding modes properly, and deprecate the existing rounding 
constants in the future to get rid of the confusing names.

I wanted to know if anyone has any object to introducing this new enum and 
signature change.
The only thing I could think of is if this enum should be in a new Maths (or 
Math or just Mathematics to not need to deal with regional difference in the 
short spelling of "Mathematics") namespace.

Best regards,

Gina P. Banyard

[1] https://wiki.php.net/rfc/adding_bcround_bcfloor_bcceil_to_bcmath
[2] https://en.wikipedia.org/wiki/Rounding
[3] 
https://www.calculatorsoup.com/calculators/math/rounding-methods-calculator.php
[4] https://wiki.php.net/rfc/new_rounding_modes_to_round_function

Reply via email to