Re: [PHP-DEV] Proposal: Arbitrary precision native scalar type

Sorry for the so late reply, but I would like to continue the
discussion on this topic.

On Tue, Dec 12, 2023 at 10:04 PM G. P. B. <george.banyard@gmail.com> wrote:

I didn't know that the strict types directive was a mistake. My intention is to be able to write clean all-decimal units of code and not break the backward compatibility. The old code should work as it was before. At the same time, there are use cases when the whole class/project should be written with decimals only. As a user, I want to do that without complex language structures and excessive typehints or explicit conversions. The all-decimal code should be as clean as it is now with floats. This is why I proposed this directive. Can you suggest something better to achieve the same?

The issue is that I don't think having arbitrary precision decimals as a core language feature is a necessity compared to rational types.
A cast from rational to float wouldn't produce a large round trip, whereas trying to figure out arbitrary precision is more difficult.
But in any case, having a declare/INI or whatever that changes the behaviour of the engine/language is not a good design choice.

How can we introduce the ability to write user code in default
decimals and at the same time keep the old way of working as it was
before, to not introduce any troubles into the existing code and not
introduce performance issues? As a user, I would like to have a
choice. When I need speed and I don't care about rounding errors, I
will use default floats. When I need precise calculations and can
sacrifice some performance, I will use default decimals. And I would
like to be able to switch between these modes selectively, not
app-wide. Just give me a choice and inform me in the documentation
about the differences and pros/cons of both types.

I'm not in the context of the core team plans regarding "strict
types". Could you share some details here? What is the current plan
regarding it? To make strict types on by default eventually? Or
something else?

If you can suggest a better way of working with fractional numbers - please do :slight_smile: But IMO limiting the language by 64 bits is not a good way. It is more easy to go over the limit than you may think :slight_smile: Especially in some intermediary values while performing complex calculations. I could be wrong, but fractional numbers limited to 64 bits sound like a bandaid. The language will tell users "hey, you can do something general, but if you want something else please don't use me at all or involve bandaids with extensions". My key point is not only to allow working with decimals, but also to make all the alternatives useless, cover their functionality by builtin tools, to free users from thinking about workarounds and bandaids. From my POV, introducing a new decimal type that does not cover the GMP/bcmath/ext-decimal functionality is pointless and a waste of time.

Again, the use cases for arbitrary precision numbers seems rather limited, and having this as an extension does not seem problematic at all.
My current issue is that there is no way to represent "small" numbers such as 0.1 or 5.8 exactly.
Arbitrary precision is a totally different ballpark, be that for integers and/or fractional values and makes everything slow, just look at Python who is *finally* investing time and money to make the most common numbers (those that fit in a machine word) not be abysmally slow.

Honestly speaking, my current pain point is that I need to work with
precise money calculations in business automation and accounting
fields. I would like to see a good tool in the PHP language to do
that. As an engineer, I understand that it should be fast enough. I
suggested mpdecimal as a good enough option. If you could suggest
something else that would fit the majority of user needs, I'm totally
for it.

How quickly you would be able to read something like this: gmp_add(gmp_mul(gmp_div(gmp_sub($value, $add), $value2, $factor, gmp_sin($value3), gmp_intval($value))) ?

This absence of intuitive readability makes the development and support difficult and it's better to choose another language. This is what I want to change and make PHP powerful enough for this kind of applications.

GMP supports operator overloading, so you do not need to write this, and as far as I see, ext/decimal *also* supports operator overloading so you can just write it using the normal arithmetic operations.
Moreover, it supports type casts so you can just do (int) $GMP instead of gmp_intval($GMP);
And it also supports using the comparisons operatos on it instead of using gmp_cmp()

The only thing that is, currently, not possible to do is a cast _to_ GMP using (GMP), but maybe that's something that could be added to the engine for internal objects, but I'm not sure about this.

If GMP can be converted to a scalar builtin language type, that also
will be totally fine from my point of view.

It seems, your main motivation to have this as a language feature is to have access to operator overloading and casting behaviour, that internal objects already support.

My points are the following:
- Work with scalar numeric types when I work with numbers, not with
objects or strings mimicking numbers. I want (bool)Decimal(0) to be
equal to false, not to true because non-null objects are always true.
- Have it as a built-in language feature allowing anyone to use it
without requiring extension installation.
- Keep backward compatibility for the code that already works with
floats while introducing an option to use only the new type when
performing math operations on numbers. And being able to have two
versions of the code working in the same app.
- IDEs and static analyzers sometimes go crazy when I do math
operations or comparisons on objects.

Which diminish the cost/benefit of making the engine changes, especially if the default behaviour doesn't change and one needs to maintain effectively two different versions of PHP depending on if it is in "decimal" or "floating" mode, which raises a plethora of questions just in its own.

As a developer, I don't see an issue with having two fractional
numeric types in the language. My old code with floats is working as
usual and doesn't break. If I want to introduce precise calculations
for money/accounting/whatever using decimals, I change my code and I'm
fully responsible for its maintenance. PHP has warnings to inform
developers if they do something wrong and this is what can be used to
prevent errors in the code. The only problem here that I foresee is
the division on two ints (and some other operations I think) should
return some specific type (float or decimal) and the language needs a
mechanism to determine the intention and return the proper result
type. This is why I suggested using "declare". In other cases, if at
least one of the operands is decimal we can always return decimals.

On 18/03/2024 04:39, Alexander Pravdin wrote:

I'm not in the context of the core team plans regarding "strict
types". Could you share some details here? What is the current plan
regarding it? To make strict types on by default eventually? Or
something else?

PHP doesn't really have a defined "core team". There are contributors who are particularly active at a given time (sometimes, but far from always, because someone is paying them), contributors who are particularly long-standing and respected, contributors who throw themselves into a pet project and make it happen, and so on.

Partly as a consequence of this, it's often hard to pin down any long-term plan about anything, outside of what particular people would like to see. So Gina's opinion (it was suffixed "IMHO") that strict types was a mistake shouldn't be read as "we have a solid plan for what is going to replace strict_types which everyone is on board with".

I think a reasonable number of people do share the sentiment that having two separate modes was a mistake; and neither mode is actually perfect. It's not about "making it on by default", it's about coming up with a unified behaviour that makes the setting redundant.

All of which is something of a diversion from the topic at hand, which is this:

How can we introduce the ability to write user code in default
decimals and at the same time keep the old way of working as it was
before, to not introduce any troubles into the existing code and not
introduce performance issues? As a user, I would like to have a
choice.

I don't think choice is really what you want: if you were designing a language from scratch, I doubt you would say "let's give the user a choice of what type 1 / 10 returns". What it's actually about is *backwards compatibility*: what will happen to code that expects 1/10 to give a float, if it suddenly starts giving a decimal.

For most cases, I think the rule can be as simple as "decimal in means decimal out". What's maybe not as obvious at first sight is that that can apply to operators as functions, and already does: 100 / 10 gives int(10), but 100.0 / 10 gives float(10.0), as do 100 / 10.0 and 100.0 / 10.0

By the same logic, decimal(1) / 10 can produce decimal(0.1) instead of float(0.1), and we don't need any fancy directives. Even better if we can introduce a shorter syntax for decimal literals, so that it becomes 1_d / 10

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.

In short, the best way of avoiding declare() directives is not to replace them with something else, but to choose a design where nobody feels the need for them.

Regards,

--
Rowan Tommins
[IMSoP]

On Mon, Mar 18, 2024 at 1:35 PM Rowan Tommins [IMSoP] <imsop.php@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

On 04/04/2024 02:29, Jordan LeDoux wrote:

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.

I haven't followed the discussion in the other thread, but I'm not sure what the use case would be for a "fixed scale decimal" that followed those rules.

As mentioned before, the use case I've encountered is money calculations, where what people want to fix is the smallest unit of account - e.g. €0.01 for practical currency, or €0.0001 for detailed accounting / trading.

If I write $total = 1.03_d2; $perPerson = $total / 2; I want a result of 0.51_d2 or 0.52_d2 - that's why I specified a scale of 2 in the first place.

If I want an accurate result of 0.515_d3, I would just specify 1.03_d, since the scale hasn't had any effect on the result.

If I want a lossless split into [0.51_d2, 0.52_d2] I still need a function to exist somewhere, whether you spell that $total->split(2), or decimal_split($total, 2), etc. So it seems safer to also have $total->div(2, Round::DOWN) or decimal_div($total, 2, Round::DOWN) and have $total / 2 give an error.

Possibly, it could only error if the result doesn't fit in the scale, so that this would be fine: $total = 11.00_d2; $perPerson = $total / 2; assert($perPerson === 5.50_d2)

Or possibly, it would just be an error to perform division on a fixed scale decimal, but allowed on a variable-fixed scale decimal.

Regards,
--
Rowan Tommins
[IMSoP]

On Thu, Apr 4, 2024 at 2:28 PM Rowan Tommins [IMSoP] <imsop.php@rwec.co.uk> wrote:

I haven’t followed the discussion in the other thread, but I’m not sure
what the use case would be for a “fixed scale decimal” that followed
those rules.

As mentioned before, the use case I’ve encountered is money
calculations, where what people want to fix is the smallest unit of
account - e.g. €0.01 for practical currency, or €0.0001 for detailed
accounting / trading.

If I write $total = 1.03_d2; $perPerson = $total / 2; I want a result of
0.51_d2 or 0.52_d2 - that’s why I specified a scale of 2 in the first place.

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. They generally want maximum precision that is computationally reasonable, and then round it according to their preferred method at the end. Doing the calculations as you are suggesting would introduce a maximum error of several cents/pence/etc. after only two or three calculations, which is utterly useless for most applications that deal with money.

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.

If I want an accurate result of 0.515_d3, I would just specify 1.03_d,
since the scale hasn’t had any effect on the result.

If I want a lossless split into [0.51_d2, 0.52_d2] I still need a
function to exist somewhere, whether you spell that $total->split(2), or
decimal_split($total, 2), etc. So it seems safer to also have
$total->div(2, Round::DOWN) or decimal_div($total, 2, Round::DOWN) and
have $total / 2 give an error.

I mean, what you are describing is how such OBJECTS are designed in other languages like Python, but not scalars. Python also has (almost completely unrestricted) userland operator overloading, which PHP does not, which further makes the comparison a little murky.

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.

Possibly, it could only error if the result doesn’t fit in the scale, so
that this would be fine: $total = 11.00_d2; $perPerson = $total / 2;
assert($perPerson === 5.50_d2)

Or possibly, it would just be an error to perform division on a fixed
scale decimal, but allowed on a variable-fixed scale decimal.

Maybe we’re just not understanding each other. Are you opposed to the idea of doing this as a scalar? It certainly feels that way. This feels more like an argument in favor of doing object-like numerics for this. I suppose that isn’t really that strange either, because as I noted such a value will almost certainly need to be refcounted because it will not fit into the 64 bits available for a zval no matter what underlying library is used to perform the math.

Jordan

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 GitHub - brick/money: A money and currency library for PHP 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 GitHub - brick/money: A money and currency library for PHP 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]

Hi,

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.

IMHO, if need a parameter that is anything other than a pure value, it’s a bad fit for a native type. It’s just a different notation for creating instances.

If we really wanted decimal to be a native type, then the rounding mode and scale behavior should be completely fixed and not user selectable. If not, decimal should be implemented as a class. In fact, php’s float will round values ​​that are too fine, and cannot specify how it will round them. (This involves CPU floating point modes, but I wanted to keep it consistent so I just gave it as an example.)

Regards.

Saki

On 07/04/2024 14:27, Saki Takamachi wrote:

If we really wanted decimal to be a native type, then the rounding mode and scale behavior should be completely fixed and not user selectable. If not, decimal should be implemented as a class.

As I replied to Jordan, I don't see why this is connected to "scalar" vs "object" types at all. An object - particularly an immutable one - is just a way of declaring a type, and some syntax for operations on that type. There's really no difference at all between these:

$half = $whole / 2;
$half = numeric_div($whole, 2);
$half = $whole->div(2);

In PHP, right now, the last one is only available on objects, but there have been proposals in the past to change that; it's just syntax.

For rounding, the first one is the real problem, because there's nowhere to put an extra operand. That problem is the same for a class with an overloaded "/" operator, and a "scalar" type which has a definition of "/" in the engine.

Maybe it feels more obvious that an object can carry extra state in private properties, but internal types don't actually need private properties at all. PHP's "array" type has a bunch of different state without being an object (a linked list of items, a hashtable for random access, an iteration pointer, etc); and SimpleXMLElement and DOMNode are exposed in PHP as separate classes, but actually store state in the same C struct provided by libxml2.

So I see it just as an API design decision: do we specify the rounding mode of numeric division a) on every operation; b) on every value; c) in a runtime setting (ini_set); d) in a lexically scoped setting (declare)?

My vote is for (a), maybe with (d) as a fallback.

Regards,

--
Rowan Tommins
[IMSoP]

On Mon, Apr 8, 2024 at 5:06 PM Rowan Tommins [IMSoP]
<imsop.php@rwec.co.uk> wrote:

If we ever do want to make decimals a native type, we would need some way to initialise a decimal value, since 1.2 will initialise a float.

My original suggestion was:

- Add "default decimal" mode with the "declare" statement in the
beginning of the file. With this statement, all decimal literals like
1.2 will compile to decimals internally, not to floats.
- Add "(decimal) 1.2" typecast that will compile to a decimal number
representation when there's no "default decimal" statement in the
file.

So users will be able to switch contexts explicitly and always know
what they're dealing with.

--
Best, Alexander.

On Tue, Mar 19, 2024 at 5:35 AM Rowan Tommins [IMSoP]
<imsop.php@rwec.co.uk> wrote:

I think a reasonable number of people do share the sentiment that having two separate modes was a mistake; and neither mode is actually perfect. It's not about "making it on by default", it's about coming up with a unified behaviour that makes the setting redundant.

This is off-topic, but just to conclude: as a user, I personally would
love to see strict_types to be always enabled eventually.

I don't think choice is really what you want: if you were designing a language from scratch, I doubt you would say "let's give the user a choice of what type 1 / 10 returns". What it's actually about is *backwards compatibility*: what will happen to code that expects 1/10 to give a float, if it suddenly starts giving a decimal.

In short, the best way of avoiding declare() directives is not to replace them with something else, but to choose a design where nobody feels the need for them.

I understand your point and it is completely valid. But I'm speaking
from a different angle. There are obviously two opposite areas of
calculations, two "modes": "I don't care much about the performance,
give me precise results" and "I don't care about rounding errors, give
me the fastest results". I can't imagine a way of joining them and
unifying the work with them until a completely new CPU architecture is
invented. It makes me think "how can we make both types of users
happy"? I would like to see native and intuitive support for both of
the "modes". So "declare(default_decimal)" seems to be a good option.
Users already know what is "declare" so it will be not a problem to
start using another option. Again, I'm not trying to replace float
calculations with decimals due to performance and backward
compatibility. My goal is to invent a way to make two "modes"
convenient without bandaids.

For most cases, I think the rule can be as simple as "decimal in means decimal out". What's maybe not as obvious at first sight is that that can apply to operators as functions, and already does: 100 / 10 gives int(10), but 100.0 / 10 gives float(10.0), as do 100 / 10.0 and 100.0 / 10.0

I agree that if one of the operands is decimal then the result should
be decimal. The "declare(default_decimal)" is suggested specifically
for the cases when it is unclear what result we should return and to
not introduce monstrous syntax with a lot of typecast or special
syntax.

By the same logic, decimal(1) / 10 can produce decimal(0.1) instead of float(0.1), and we don't need any fancy directives. Even better if we can introduce a shorter syntax for decimal literals, so that it becomes 1_d / 10

With "declare(default_decimal)" there's no need to introduce new
syntax for numbers. I personally would prefer to work with "normal"
number literals and let PHP decide (under my guidance) how to
represent them internally - as floats or as decimals.

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?

As a user, I see it as we store a decimal number internally with the
maximum number of fractional digits and let the user choose how to
represent it only when converting it from decimal to something else.
Only at this moment, some rounding will happen and we may give users
the proper tools for this. When it comes to 1/3, we may hardcode some
specific rounding mode when it exceeds the internal limit of
fractional digits. In my view, this limit will be more than enough for
99.9% of so they will be able to apply their own rounding mode to 0 or
2 or 10 fractional digits with no issues.

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.

Yes, but the whole point of my suggestion is to go away from the
object syntax :slight_smile: My goal is not to make the future implementation
simpler but to lift the PHP language to the next level even if will
cost much more effort in total.

And just to clarify. I'm not a big expert in decimal calculations, my
proposal is still not so specific and I may have a lack of knowledge
in some terms or details and may need help from more experienced
people. I'm discussing possible ways of the implementation and I would
like to help the community to develop some design that will make
future development aligned with some principles and eventually achieve
the final goal. I understand the complexity of the proposal so I'm not
standing on the implementation as a whole by some PHP version. But I
would be more than happy to know that the language is evolving in the
defined direction.

--
Best, Alexander

On Wed, 3 Apr 2024, Jordan LeDoux wrote:

On Mon, Mar 18, 2024 at 1:35 PM Rowan Tommins [IMSoP] <imsop.php@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:

Woound't it be much better to capture this complex information in an
Object, and then allow operators on this? Like... Saki was pretty much
suggesting with her BCMatch/Number class RFC?

I can't imagine people looking at code understanding a syntax like this
right away, let alone of what it all means.

cheers,
Derick

--
https://derickrethans.nl | https://xdebug.org | https://dram.io

Author of Xdebug. Like it? Consider supporting me: Xdebug: Support

mastodon: @derickr@phpc.social @xdebug@phpc.social