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