Remix.run Logo
gucci-on-fleek 8 hours ago

What do you recommend instead? Standard floating-point ("float"/"double"), fixed-point arithmetic with thousandths (or smaller) of the minor unit, arbitrary-precision decimal numbers, or something else entirely?

lxgr 8 hours ago | parent | next [-]

I think what matters most is your database and API representation, as well as having consistent and well-defined rounding rules.

I largely agree with TFA: Round explicitly and consistently whenever you cross a boundary, i.e. database persistence and internal API calls.

Use whatever works for your required business case internally (i.e. inside of procedures calculating some function of one or more input amounts). This can be regular old floats/doubles if you absolutely know what you're doing, or BigDecimal if you aren't and would rather suffer slightly slower performance than having to talk to an auditor about IEEE 754 rounding modes, or even minor-amount integers (yes, even though I just said to not use them – but you'll want to ABSOLUTELY NEVER leak them outside of your system, including your data/analytics pipeline, which might have different ideas about financial amounts than your business logic implementing a nice custom monetary type).

ivanmontillam 8 hours ago | parent | prev | next [-]

A string type. As parent says: it completely bypasses the problem. Save the numbers between double quotes and be done with it.

lxgr 5 hours ago | parent | next [-]

Except that now you have a new problem: Opinionated theorists that haven’t been part of a nasty “oh no, we accidentally considered some amounts as 10x/100x/1000x larger/smaller than expected” incident in their career yet…

portly 7 hours ago | parent | prev [-]

Storing numbers as arrays of u8? That doesn't make sense

ivanmontillam 6 hours ago | parent | next [-]

For JSON serialization, which doesn't support fixed-point precision it does.

Floating-point precision has too many gotchas for being suitable to store Decimal types, especially for the Currency use case.

notpushkin 6 hours ago | parent [-]

Surely it does:

  {
    "price": {
      "amount": 1000,
      "decimal_places": 2,
      "currency": "USD"
    }
  }
lxgr 6 hours ago | parent [-]

How is that better than {“amount”: “10.00”} (which also bypasses all potential floating point parsing issues that your or your counterparty’s JSON library might have)?

jameshart 5 hours ago | parent [-]

It is explicit about the fact that that number of decimal places is part of the data.

The semantics for your string “10.00” are complex - is it considered equal to “10”? To “10.000”? To “10.001”?

A user interacting with an API that uses such a string might make all sorts of assumptions about what it supports.

A user interacting with an API that has an explicit decimal places concept is being told ‘decimals matter! They can vary! Here be dragons!’

lxgr 4 hours ago | parent [-]

> The semantics for your string “10.00” are complex - is it considered equal to “10”?

Yes, but "10 USD" would be a non-canonical representation and you probably serialized incorrectly.

> To “10.000”?

Yes, but same caveat as above applies.

> To “10.001”?

Obviously not, and any system you'd ever want to use in a financial context will tell you so.

lxgr 6 hours ago | parent | prev [-]

It makes a lot of sense if you value correctness over performance.

microgpt 5 hours ago | parent [-]

Why not store them in unary then?

lxgr 5 hours ago | parent [-]

Unary is exactly as expressive as decimal or binary for integers, but somewhat less efficient, so why would you?

microgpt 4 hours ago | parent [-]

idk, why would you store integers as ASCII strings? It's somewhat less efficient.

lxgr 3 hours ago | parent [-]

Because it's much more explicit. Computers are fast, engineering is expensive. You usually never want to optimize prematurely when dealing with monetary amounts.

KellyCriterion 7 hours ago | parent | prev | next [-]

Do not throw away any precision in finance/money computation, regardless what/ how you are doing it.

In C# e.g., there is type decimal for those computations.

lxgr 7 hours ago | parent [-]

You'll definitely have to throw it away at some point.

The art is in making those points well-defined and rare enough to not cause large discrepancies, but frequent enough to avoid ballooning arbitrary-precision numbers across databases and services that might not be able to handle them.

krever 6 hours ago | parent [-]

I really like that phrasing! Would you mind if I steal in some form if I decide to review this part of the book?

lxgr 6 hours ago | parent [-]

Not at all, and thanks for writing all of this up!

necrotic_comp 7 hours ago | parent | prev [-]

Floating point value stored multiplied by 10^8. That gives you a huge integer, but it's extremely accurate, especially for US denominated currencies. Easily transformed into floating point numbers for reporting/etc.

5 hours ago | parent [-]
[deleted]