View Issue Details

IDProjectCategoryView StatusLast Update
4884Composrecommercepublic2022-08-11 17:48
ReporterChris Graham Assigned ToGuest  
PrioritynormalSeverityfeature 
Status newResolutionopen 
Summary4884: Support for CURRENCY data field (on hold)
DescriptionFloating 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.
TagsNo tags attached.
Attach Tags
Time estimation (hours)32
Sponsorship open

Sponsor

Date Added Member Amount Sponsored

Relationships

related to 3046 Not AssignedGuest Drop 32-bit support (on hold) 

Activities

Chris Graham

2022-08-11 17:48

administrator   ~7425

An alternative is to support a new REAL_DOUBLE data field type, once 3046 is implemented (i.e. once we know we can use it in PHP code). This solves the problem of inflated currencies, and reduces the chance of accuracy errors - but it is not as clean.
Or, to use BIGINT, once 3046 is implemented and deal in cents. Probably not very future proof and somewhat messy.

For reference, I looked into it and MySQL 32 bit can handle BIGINT (64 bit), DOUBLE (64 bit), and very long DECIMAL up to 65 digits. This is because it uses either advanced CPU instructions or compiler magic to work beyond the system architecture's word size.

Add Note

View Status
Note
Upload Files
Maximum size: 32,768 KiB

Attach files by dragging & dropping, selecting or pasting them.
You are not logged in You are not logged in. This means you will not get any e-mail notifications. And if you reply, we will not know for sure you are the original poster of the issue.

Issue History

Date Modified Username Field Change
2022-08-11 02:03 Chris Graham New Issue
2022-08-11 02:03 Chris Graham Relationship added related to 3046
2022-08-11 17:44 Chris Graham Description Updated
2022-08-11 17:48 Chris Graham Note Added: 0007425