Hacker News new | past | comments | ask | show | jobs | submit login
Never Use Floats for Money (2016) (husobee.github.io)
52 points by adunk 6 days ago | hide | past | web | favorite | 37 comments





This type of thing coming from programmers really bothers me. Here is a more universal rule: Never say "never."

Whether or not floating point numbers can be used depends on the context. If you are talking about an accounting system, core banking system, ERP, or similar transactional systems, then sure you probably should use integers not floats.

However, if you're working on any financial model, like something as simple as discounted cash-flow model, then floating point is the correct choice and only choice.

I've had a programmer try to convince me that I had to use integers in financial modeling software that I was developing, and he used this same folksy argument with me. It was a genuine struggle to convince him that this was not a universal law and made no sense for the application at hand.


Right. For example, potential insurance losses are only known approximately, so floating point is what should be used in their modeling.

I’ve built two different payment platforms in the past, I’m curious why floating point is the correct and only choice for financial modeling.

Quantization error is irrelevant in modelling so far as the datatype has the appropriate dynamic range. You don't care about the rounding errors, you care about the speed of execution of your model and how able it is to find trends/behaviors. Exact values aren't useful.

It can't be worth any microscopic performance benefit to not just be safe/precise and substitute a decimal datatype in 99% of cases. Something crazy like HFT might be an exception, or if it's just a quick excel sheet. Otherwise it's still a perfectly good rule of thumb to keep money in decimal types if you're writing code.

It's not about performance.

Modeling (including financial modeling) requires transcedental functions and real numbers.


I'd qualify the statement a bit and say, don't use floats for accounting. It's a tradition that the last column of an accounting calculation is a kind of crude error checking code.

I think if you're doing financial modeling, or anything where the real uncertainty is bigger than your unit of money, then it's like any other calculation -- use floats with all of the cautions that you learned in numerical analysis class.

My dad played the stock market and used a slide rule for his calculations.

Another reminiscence: Since he owned some stocks, my dad got annual reports. I remember leafing through the report from General Motors, and seeing that all of the numbers were given at full precision, down to the penny. I remember thinking to myself: If one worker accidentally carries a pencil home, those numbers are all wrong!


I remember hearing this back when I worked on financial software for hedge funds (2005ish), adjusting our product so it represented currencies as integer numbers of cents, taking the change to my boss (the company CEO), and then hearing "Use floats for money. All of our customers do, and if we don't you'll create needless friction for them."

Ran into it more recently when doing cryptocurrency market analytics. Bitcoin represents currency as integer numbers of satoshi, where 100M satoshi = 1 BTC. Ethereum represents it as integer numbers of wei, where 10^18 wei = 1 ETH. I thought I'd be smart and use these fundamental units internally, only to find out that basically every exchange quotes prices in floats. By the time you get the data, it's already lost whatever precision it had, and you're just introducing needless friction by trying to get smart.

Sometimes being compatible is more important than being correct.


> and then hearing "Use floats for money. All of our customers do, and if we don't you'll create needless friction for them."

Until a competent customer doesn't, then you've got to explain to them why your calculations are intentionally wrong, never a good look. Regulatory bodies also tends to want the correct decimal numbers.


If 99% of your customers do things the wrong way and 1% wants to do it the "correct" way that you don't support, there's an easy business call: you do it the way the 99% want and tell the 1% "Sorry, we don't support that. Hopefully you'll find a provider who does." Massive portions of the economy are built upon that principle, from IE6 to UNIX to C to VHS to QWERTY to 120V electricity to U.S. custom measurements to MM/DD/YYYY date formats to the use of decimal (as opposed to binary) subdivisions in the first place.

Context matters too: both of these examples are financial modeling as opposed to transactions, where (as riskneutral's sibling comment points out) floating point error is swamped by the errors in your models in the first place, and some concepts can't be modeled at all with integers. Also regulators explicitly don't care about this area: if your models give incorrect results and you trade on them that's your problem.


> Sometimes being compatible is more important than being correct.

It's a simple conversion for the sake of precision. If you are dealing with money transactions, you should strive for precise values wherever and whenever possible.


If your customers are already using floats, precision has already been lost. They're sending you data that already has floating-point round-off. If you then treat that as integer numbers of cents, you're adding additional round-off error by converting their 23 bits of binary precision to 2 digits of decimal precision. It's better to use the same format they do so that all floating-point error occurs within their systems, where it's known, has presumably been judged to be low-risk, and can be compensated for, rather than silently and unpredictably add new sources of error that your customers don't know about.

Fun Fact: Microsoft Excel uses double precision floating point numbers. Much of the world's numbers are run through Excel. I feel like some people have probably just ended up using the same floats themselves, just so that their boss's spreadsheet agrees with their numbers...

https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft...


As does Javascript of course. On the other hand, IEEE754 guarantees correct rounding, so floating point operations on integral values will come out alright (additions and multiplications will be exact within a large range, and inexact divisions will be rounded correctly, so you shouldn't be any worse than using integer operations).

More time has passed between Office Space (1999) and today than between Office Space and Superman 3 (1983).

the perennial stackoverflow question -> https://stackoverflow.com/questions/3730019/why-not-use-doub...

A real life example: in the R language, this statement resolves to FALSE

    > 74.20+153.20==227.40
    [1] FALSE

I agree that you should not use floating numbers for amounts of money (maybe with some kind of calculations it might be suitable, but this is rare), but I do not deal with calculations involving money on the computer so much. But, yes normally integers are better for the amount of money (and for some other stuff that normally involves fractions, too; if fixed point is suitable (as is the case for money), then integers are probably better than using floating point). (Comment 22322487, and its replies, also mentions why sometimes floating point is used, but normally to record amounts of money, integers are better. As other comments mention, sometimes you might even use other types such as rational type.)

In the past (1990s) there have been banks caught skimming. They were always exchanging (with other banks) amounts of currency (fe EUR to USD) specifically chosen so the error was always in their favour.

The article is right, you should use integers for the number of cents (or whatever the smallest unit of the currency is). That is easy enough as long as you are just adding and subtracting, but what do you do about multiplication and division? How do you calculate interest or yearly yields? I think the answer is fixed point, but that is not easy.

What problem do you see with multiplication or division? You can still do those with the precision you need, followed by the legally valid rounding for the use case.

Unless you don't have a use case where those are defined/relevant, then ¯\_(ツ)_/¯


No, the answer is floating point.

How do I properly handle Money on the web frontend side?

on the backend I have python's exquisite Decimal() which covers all bases and is base-10

how would one guarantee that precision when you have to serialize it into json and that's gonna become a normal double in JS?


There are libraries, such as Dinero.JS [0] or Decimal.js (handles decimals as strings). Alternatively, don't use decimals and always convert everything to cents.

[0]https://frontstuff.io/how-to-handle-monetary-values-in-javas...


In terms of purity, sure, but pragmatically, meh. You do need to round to cents in ui and after every calculation though. Exercise: how large do amounts need to be before losing a penny?

I used to evangelize integer cents but then I worked on a few systems with floats and the world didn't fall over.



Great advice on going for the lowest (cents) so you can work with integers. I do something similar with dates on all my apps where I go for ints in the database and always save unix timestamps. I can't stand dates unless I'm working with timestamps.

Same! Dates are one of the biggest sources of programmer error in my experience, and representing them as ints until they are rendered to a UI prevents a lot of it.

Actually, using timestamps for all dates is a bit like using floats for currency. For many cases it doesn't matter, but you lose information.

I tried a small C++ program and it does not exhibit this behavior. Why is it not showing there?

program: #include <iostream>

using namespace std;

int main(int argc, char argv) { float s = 165 * 1.40; cout << s << endl; }

output: ./floats 231



thanks!

Use a big decimal library with the precision you need, overload the serialization methods for your preferred data store and be done with it.

I just use blobs for everything. Just in case.

I can see a whole heap of issues using integers and cents when it comes to VAT calculation.

Use a rational type :)

I rather like this approach. It easily handles sub-cent transactions with any desired degree of precision (e.g. internal computations using the 9/10 cent bs at gas pumps). Internally everything is a rational quantity, and you just need to maintain correct (de) serialization at the system boundaries.

That all gets thrown out the window when somebody really wants an exchange rate of pi for god knows why, but satisfying every real number is impossible, and satisfying every computable number exposes you to things like the halting problem, so having a system that just supports rationals seems like a good compromise.


Money is real.



Applications are open for YC Summer 2020

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: