On Mon, Mar 18, 2024 at 1:35 PM Rowan Tommins [IMSoP] <imsop....@rwec.co.uk> wrote:
> > Where things get more complicated is with *fixed-precision* decimals, > which is what is generally wanted for something like money. What is the > correct result of decimal(1.03, precision: 2) / 2 - decimal(0.515, 3)? > decimal(0.51, 2)? decimal (0.52, 2)? an error? And what about decimal(10) / > 3? > > If you stick to functions / methods, this is slightly less of an issue, > because you can have decimal(1.03, 2)->dividedBy(2, RoundingMode::DOWN) == > decimal(0.51, 2); or decimal(1.03, 2)->split(2) == [ decimal(0.52, 2), > decimal(0.51, 2) ] Example names taken directly from the brick/money > package. > > At that point, backwards compatibility is less of an issue as well: make > the new functions convenient to use, but distinct from the existing ones > I came back to this discussion after my last reply on the BCMath as an object thread, because we went through a very similar discussion there with regard to operators. I think that, roughly, the fixed precision should be defined on the scalar itself: 1.234_d3 1.234 is the value, _d makes it a decimal type, and 3 shows that this value has a precision of 3. (Actually, it has a SCALE of 3, since precision is significant digits, and also includes the integer portion). But when it comes to fixed-precision values, it should follow rules very similar to those we discussed in the BCMath thread: - Addition and subtraction should return a value that is the largest scale/precision of any operands in the calculation. - Division and multiplication should return a value that is the sum of the scale/precision of any operands + 2 or a default (perhaps configurable) value if the sum is small, to ensure that rounding occurs correctly. Near zero, floats have about 12-ish decimal digits of accuracy, and will return their full accuracy for example. - Pow is extremely difficult to work with if you allow a decimal in the exponent. The libraries we have discussed previously handle this difficulty, but the precision needed often depends on what the calculation is for, so I'm not entirely sure what the best way to handle this with operators would be. Minimally, probably the same as division and multiplication. But if we have scalar decimal types, we need something like that _d12 to denote a decimal scalar with a scale/precision of 12. Jordan