Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: currency #37

Open
ladd opened this issue Nov 2, 2021 · 4 comments
Open

Feature request: currency #37

ladd opened this issue Nov 2, 2021 · 4 comments

Comments

@ladd
Copy link

ladd commented Nov 2, 2021

Currency amounts are a common use case for APIs.

In a typical JSON implementation, you often see something like:

{"amount": 5.00, "currencyId": "USD"}

^ This is incorrect, since most parsers will treat the number amount as a floating point value, leading to rounding errors when performing financial calculations. It's also not particularly compact.

A slightly better alternative is:

{"amount": "5.00", "currencyId": "USD"}

This assumes that the receiving end knows enough to convert the amount field to a BigDecimal-equivalent type.

It's also fairly common to see:

{"amount": 500, "currencyId": "USD"}

This assumes that the receiving end knows that the value is expressed in pennies. This also makes it difficult to express sub-penny amounts.

To express this correctly, it would be extremely useful to have a currency type that combines an arbitrary precision decimal with a currency code. Alternatively, just decimal support would be sufficient. In the Java model, this is expressed as an "arbitrary precision integer unscaled value and a 32-bit integer scale".

Using the numeric currency codes described in the spec would be more compact, although not as human readable without an up-to-date mapping table: https://en.wikipedia.org/wiki/ISO_4217

I'd be happy to take a crack at adding this to the spec if there's interest.

@kstenerud
Copy link
Owner

Hi, thanks for your interest!

CE supports decimal floating point numbers to arbitrary precision and size, which should handle currency values without losing anything to rounding. In the text format, numbers in decimal notation always represent decimal values. To represent binary float values, you must use the hex float notation (so that no loss to conversion rounding can occur).

So in this case you could do:

{"amount"=5000000000000.0001 currencyId="USD")

I'm trying to resist the temptation to add compound types to the spec. The general philosophy is: Fundamental types yes, compound types mostly not. The only exceptions I've made so far are time and media because they're so uniquitous and prone to compatibility issues. Currency as a compound of decimal float + string is probably enough to be understood or at least workable without too much trouble. For high speed trading systems that need to move a LOT of currency values, you'd probably want a struct-based format like flatbuffers anyway since marshalling would be an order of magnitude faster in such a use case.

@ladd
Copy link
Author

ladd commented Nov 4, 2021

Makes sense -- I guess having a strong recommendation to use a true decimal type in implementation might make this more clear:

From https://github.com/kstenerud/concise-encoding/blob/master/cte-specification.md#base-10-notation

For example, 64-bit ieee754 floating point values can represent values with up to 16 significant digits and an exponent range roughly from 10⁻³⁰⁷ to 10³⁰⁷.

^ this sort of implies that using ieee754 floating point would be a good idea.

@kstenerud
Copy link
Owner

Hmm that's true... It's gone through so many revisions that the nuance has been lost. Binary float was supposed to be mainly for legacy support. I'll update things to make it more clear!

It's a real shame that ieee754-2008 decimal type adoption is so slow.

@kstenerud
Copy link
Owner

kstenerud commented Nov 5, 2021

26898b2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants