Re: [RFC] [Discussion] Support object type in BCMath
| From: | Saki Takamachi | Date: | Sun, 31 Mar 2024 00:09:18 +0000 |
| Subject: | Re: [RFC] [Discussion] Support object type in BCMath | ||
| References: | 1 2 3 4 5 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-122832@lists.php.net to get a copy of this message | ||
Hi Jordan,
> For addition, it absolutely should expand scale like this, unless the constructor also defines
> a default rounding type that is used in that situation. All numbers, while arbitrary, will be
> finite, so addition will always be exact and known based on inputs prior to calculation.
>
> Treating scale like this isn't more strict, it's confusing. For instance:
>
> ```
> $numA = new Number('1.23', 2);
> $numB = new Number('1.23456', 5);
>
> $expandedScale1 = $numA + $numB; // 2.46456
> $expandedScale2 = $numB + $numA; // 2.46456
>
> $strictScale1 = $numA + $numB; // 2.46 assuming truncation
> $strictScale2 = $numB + $numA; // 2.46456
> ```
>
> I ran into this same issue with operand ordering when I was writing my operator overload RFC.
>
> There are ways you could do the overload implementation that would get around this for object +
> object operations, but it's also mathematically unsound and probably unexpected for anyone who
> is going to the trouble of using an arbitrary precision library.
>
> Addition and subtraction should automatically use the largest scale from all operands. Division
> and multiplication should require a specified scale.
>
> Because of this, I'm not entirely sure that specifying a scale in the constructor is
> actually a good thing. It is incredibly easy to create situations, unless the implementation in C is
> VERY careful, where the operand positions matter beyond the simple calculation. Multiplication is
> commutative, but division is not. This would almost certainly lead to some very difficult to track
> down bugs.
>
> Putting scale in the constructor is similar to some of the examples of "possible misuse
> cases of operator overloading" that I had to go over when I was making my RFC. We definitely
> want to avoid that if possible for the first number/math object that has operator overloads.
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