#4884 - Support for CURRENCY data field (on hold)

Identifier #4884
Issue type Feature request or suggestion
Title Support for CURRENCY data field (on hold)
Status Open
Handling member Deleted
Addon ecommerce
Description Floating point numbers are currently used represent currency. I have documented the reasoning for that https://gitlab.com/composr-foundation/composr/-/commit/bc0f065d5503dd790a195dd4c164752902e640f6.

This simple command shows that using floats is unreliable:

php -r 'var_dump(number_format(0.1,100));'
string(102) "0.1000000000000000055511151231257827021181583404541015625000000000000000000000000000000000000000000000"

As I've documented, it's not usually a practical problem given how we are rounding off the numbers when converting to strings. And we use floats for good reason: PHP does not directly support fixed point maths, and dealing only with cents has its own problems.

But, it stinks frankly.

If we add a dependency on BCMath, and complexify our code, we can do better. It may not be worth the tradeoffs involved to be frank, hence why I am marking this issue 'on hold', but I wanted to get it onto the tracker.

Our data type layer uses our own abstract types to insulate us from the quirks of different DB backends. We don't need the full flexibility of different types+settings that databases support, we just need to support every usage category we have.

We could add a new data type called CURRENCY.
It would map to a DECIMAL (i.e. fixed point non-integer) on MySQL, and probably the same on every other DB driver - but this needs confirming.
We would have the precision set so we have 2 decimal places of accuracy, positive/negative, and then any remaining bits to represent the non-decimal portion.
7 bits needed for decimal places
1 bit needed for sign
32-7-1=24 bits
2^24=16777216
which is 7 digits of accuracy. That means DECIMAL(7,2) for 32 bits.
Which is accuracy up to single digit millions.
Not good enough actually, due to us wanting to cleanly support hyper-inflated currencies.
If we use 64 bits (which actually should work even on 32 bit MySQL - DECIMALS can be really huge). Let's do the math again...
7 bits needed for decimal places
1 bit needed for sign
64-7-1=56 bits
2^56=7206 trillion (I think)
which is 15 digits of accuracy. That means DECIMAL(15,2) for 64 bits.
Which is accuracy up to hundreds of trillions.

When the parameters are read in, we would use a new post_param_currency, which would check we don't have numbers exceeding the input bounds. and that are well formed. Possibly also a parameter that decides whether negatives are allowed.

Within PHP and to/from the database we would need to store as strings, due to lack of native PHP fixed number support. Any calculations within PHP would use the BCMath extension.
Steps to reproduce

Related to

#3046 - Drop 32-bit support (on hold)

Funded? No
The system will post a comment when this issue is modified (e.g., status changes). To be notified of this, click "Enable comment notifications".

Rating

Unrated