On 04/04/2024 23:31, Jordan LeDoux wrote:

Well, firstly most of the financial applications that I've worked in (I work for a firm that writes accounting software right now) do not calculate intermediate steps like this with fixed precision, or even have an interest in doing so.


My background is in e-commerce (specifically, travel) rather than finance. In that context, it's common to have a single-step operation like "per_person_price equals total_price divided by number of passengers" where both per_person_price and total_price are going to be expressed with the same accuracy.

The top two results for "money" on Packagist are https://www.moneyphp.org/ and https://github.com/brick/money both of which take this general model: the scale of values is fixed, and every operation that might produce fractions of that requires a rounding mode.


Truly "fixed-precision" is not something that decimal should even try to be, in my opinion. The use cases where you CANNOT simply round the result at the end to fit your display output or your storage location are very minimal.


In that case, why do we need to think about the scale or precision of a decimal at all? What would the syntax 1.234_d3 do differently from 1.234_d?


I mean, what you are describing is how such OBJECTS are designed in other languages like Python, but not scalars.


I don't see any connection at all between what I'm describing and objects. I'm talking about what operations make sense on a particular data type, regardless of how that data type is implemented.

To be honest, I'm not really sure what "scalar" means in this context. In PHP, we call strings "scalars" because they're neither "arrays" nor "objects"; but none of those have definitions which are universal to other languages.


This kind of precision restriction isn't something you would place on an individual value, it's something you would place on all calculations. That's why in Python this is done with a global runtime setting using `getContext().perc` and `getContext().rounding`. A particular value having a precision of X doesn't imply anything concrete about a calculation that uses that value necessarily.


Global settings avoid needing extra parameters to each operation, but don't really work for the use case I'm describing: different currencies have different "natural" scale, e.g. Japanese Yen have a scale of 0 (no fractional Yen), Bitcoin has a scale of 8 (100 million satoshis in 1 bitcoin).  A program dealing with multiple currencies will want to assign a different scale to different values.


Maybe we're just not understanding each other. Are you opposed to the idea of doing this as a scalar?


Not at all; my first examples used method syntax, because I was basing them on https://github.com/brick/money In my last e-mail, I also gave examples using normal function syntax.

What I'm saying is that $x / 2 doesn't have a good answer if $x is a fixed-precision number which can't be divided by 2 without exceeding that precision. You need a third operand, the rounding mode, so you can't write it as a binary operator, and need some kind of function like decimal_div(decimal $dividend, int|decimal $divisor, RoundingMode $roundingMode). How you implement "decimal" doesn't change that at all.


Regards,

--
Rowan Tommins
[IMSoP]

Reply via email to