On Sat, Mar 30, 2024 at 5:09 PM Saki Takamachi <s...@sakiot.com> wrote:

> Hi Jordan,
>
> Your opinion may be reasonable given the original BCMath calculation
> order. That is, do you intend code like this?
>
> Signature:
> ```
> // public function __construct(string|int $number)
> // public function getNumber(?int $scale = null): string
> ```
>
> Add:
> ```
> // public function add(Number|string|int $number): string
>
> $num = new Number('1.23456');
> $num2 = new Number('1.23');
>
> $add = $num + $num2;
> $add->getNumber(); // '2.46456'
> $add->getNumber(1); // ‘2.4'
>
> $add = $num->add($num2);
> $add->getNumber(); // '2.46456'
> $add->getNumber(1); // '2.4'
> ```
>
> Div:
> ```
> // public function div(Number|string|int $number, int $scaleExpansionLimit
> = 10): string
>
>
> // case 1
> $num = new Number('0.0001');
> $num2 = new Number('3');
>
> $div = $num / $num2; // scale expansion limit is always 10
> $div->getNumber(); // '0.0000333333333'
>
> $div = $num->div($num2, 20);
> $div->getNumber(); // '0.00003333333333333333333'
> $div->getNumber(7); // ‘0.0000333'
>
>
> // case 2
> $num = new Number('1.111111');
> $num2 = new Number('3');
>
> $div = $num->div($num2, 3);
> $div->getNumber(); // '0.370'
> $div->getNumber(7); // ‘0.3700000'
> ```
>
> Since the scale can be inferred for everything other than div, a special
> argument is given only for div.
>
> Regards.
>
> Saki


Something like the signature for `getNumber()` in this example would be a
decent solution. Operations which have ambiguous scale (of which truly only
div is in the BCMath library) should *require* scale in the method that
calls the calculation, however for consistency I can certainly see the
argument for requiring it for all calculation methods. The issue is how you
want to handle that for operator overloads, since you cannot provide
arguments in that situation.

Probably the most sensible way (and I think the way I handled it as well in
my library) is to look at both the left and right operand, grab the
calculated scale of the input for both (or the set scale if the scale has
been manually set), and then calculate with a higher scale. If internally
it produces a rounded result, the calculation should be done at
`$desireScale + 2` to avoid compound rounding errors from the BCMath
library and then the implementation. If the result is truncated, the
calculation should be done at `$desiredScale + 1` to avoid calculating
unnecessary digits.

So we have multiple usage scenarios and the behavior needs to remain
consistent no matter which usage occurs, and what order the items are
called in, so long as the resulting calculation is the same.

**Method Call**
$bcNum = new Number('1.0394567'); // Input scale is implicitly 7
$bcNum->div('1.2534', 3); // Resulting scale is 3
$bcNum->div('1.2534'); // Implicit scale of denominator is 4, Implicit
scale of numerator is 7, calculate with scale of 8 then truncate

**Operators**
$bcNum = new Number('1.0394567'); // Input scale is implicitly 7
$bcNum / '1.2534'; // Implicit scale of denominator is 4, Implicit scale of
numerator is 7, calculate with scale of 8 then truncate

This allows you to perhaps keep an input scale in the constructor and also
maintain consistency across various calculations. But whatever the behavior
is, it should be mathematically sound, consistent across different syntax
for the same calculation, and never reducing scale UNLESS it is told to do
so in the calculation step OR during the value retrieval.

Jordan

Reply via email to