On 24/03/2024 13:13, Saki Takamachi wrote:
https://wiki.php.net/rfc/support_object_type_in_bcmath
Based on the various discussions we've been having, I'd like to propose
a simplified handling of "scale".
I think there are two groups of users we are trying to help:
a) Users who want an "infinite" scale, and will round manually when
absolutely necessary, e.g. for display. The scale can't actually be
infinite in the case of calculations like 1/3, so they need some safe
cut-off.
b) Users who want to perform operations on a fixed scale, with
configurable rounding, e.g. for e-commerce pricing. They are not
interested in any larger scale, except possibly in some intermediate
calculations, when they want the same as group (a).
I propose:
- The constructor accepts string|int $num only.
- All operations accept an optional scale and rounding mode.
- If no rounding mode is provided, the default behaviour is to truncate.
This means that (new BCMath\Number('20'))->div(3, 5) has the same result
as bcdiv('20', '3', 5) which is 6.66666
- If a rounding mode is provided, the object transparently calculates
one extra digit of scale, then rounds according to the specified mode.
- If no scale is provided, most operations will automatically calculate
the required scale, e.g. add will use the larger of the two scales. This
is the same as the current RFC.
- If no scale is provided to div(), sqrt(), or pow(-$x), the result will
be calculated to the scale of the left-hand operand, plus 10. This is
the default behaviour in the current RFC.
- Operator overloads behave the same as not specifying a scale or
rounding mode to the corresponding method. Therefore (new
BCMath\Number('20')) / (new BCMath\Number('3')) will result in
6.6666666666 - an automatic scale of 10, and truncation of further digits.
Compared to the current RFC, that means:
- Remove the ability to customise "max expansion scale". For most users,
this is a technical detail which is more confusing than useful. Users in
group (b) will never encounter it, because they will specify scale
manually; advanced users in group (a) may want to customise the logic in
different ways anyway.
- Remove the ability for a Number value to carry around its own default
rounding mode. Users in group (a) will never use it. Users in group (b)
are likely to want the same rounding in the whole application, but
providing it on every call to new Number() is no easier than providing
it on each fixed-scale calculation.
- Remove the $maxExpansionScale and $roundingMode properties and
constructor parameters.
- Remove withMaxExpansionScale and withRoundMode.
- Remove all the logic around propagating rounding mode and expansion
scale between objects.
I've also noticed that the round method is currently defined as:
- public function round(int $precision = 0, int $mode =
PHP_ROUND_HALF_UP): Number {}
Presumably $precision here is actually the desired scale of the result?
If so, it should probably be named $scale, as in the rest of the interface.
I realise it's called $precision in the global round() function; that's
presumably a mistake which is now hard to fix due to named parameters.
Ideally, it would be nice to have both roundToPrecision() and
roundToScale(), but as Jordan explained, an implementation which
actually calculated precision could be difficult and slow.
Regards,
--
Rowan Tommins
[IMSoP]