concise-encoding icon indicating copy to clipboard operation
concise-encoding copied to clipboard

Feature request: currency

Open ladd opened this issue 4 years ago • 4 comments

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.

ladd avatar Nov 02 '21 17:11 ladd

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.

kstenerud avatar Nov 03 '21 07:11 kstenerud

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.

ladd avatar Nov 04 '21 23:11 ladd

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 avatar Nov 05 '21 05:11 kstenerud

https://github.com/kstenerud/concise-encoding/commit/26898b2637fe49d2165a11473cb5681bb582f6b3

kstenerud avatar Nov 05 '21 06:11 kstenerud