16 ms·
> The python example is using floats for currency. Dumb question, but what is the proper way to handle currency? Custom number objects? Strings for any number
by gentleman11 5y ago
> The python example is using floats for currency.
Dumb question, but what is the proper way to handle currency? Custom number objects? Strings for any number of decimal places?
- stickfigure 5y agoCreate a Money class, or use one off the shelf. It should store the currency and the amount. There are a few popular ways of storing amounts (integer cents, fixed decimal) but it should not be exposed outside the Money class. There's plenty of good advice in this subthread for how to represent currency inside your Money abstraction, but whatever you do, keep it hidden. If you pass around numbers as currency values you will be in for a world of pain as your application grows.
- ronnier 5y agoIn its base unit. So cents in USD. Which can be an int64 Or if your language has something specific built in, use that.
- umanwizard 5y agoNot necessarily. It depends on the application.
- ainar-g 5y ago> Or if your language has something specific built in, use that. Unless your language is PostgreSQL's dialect of SQL, apparently. https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use_money https://wiki.postgresql.org/wiki/Don%27t_Do_This#Don.27t_use...
- tzs 5y ago> In its base unit. So cents in USD. Which can be an int64. Note that if you use cents in the US so that everything is an integer then as long as you do not have to deal with amounts that are outside the range [-$180 trillion, $180 trillion] you can also use double. Double can exactly represent all integer numbers of cents in that range. This may be faster than int64 on some systems, especially on systems that do not provide int64 either in hardware or in the language runtime so you'd have to do it yourself.
- umanwizard 5y agoDepends what you’re doing. In fact it’s not always wrong to use floats for currency. For accounting you should probably use a fixed-precision decimal type.
- jacobsenscott 5y agoIf someone asks how to handle money the best answer is integers or fixed precision decimals. There may be a valid case for using floats, but if someone asks they shouldn't be using floats. Also I'm hard pressed to come up with a case where floats would work. Can you give an example?
- bidirectional 5y agoMost things in front office use floats in my experience, e.g. derivative pricing, discounting, even compound interest. None of these things are going to be any better with integers or fixed-precision, but maybe harder to write and slower.
- stevesimmons 5y agoYes, the risk management/instrument pricing part in the "Front Office" uses floats, because the calculations involve compound interest and discount rates. And the downstream parts for trade confirmation ("Middle Office"), settlement and accounting ("Back Office") used fixed precision. Because they are fundamentally accounting, which involves adding things up and cross-checking totals. These two parts have a very clear boundary, with strictly defined rounding rules when the floating point risk/trading values get turned into fixed point accounting values.
- umanwizard 5y ago> Can you give an example? The answer is the same as _any_ time you should use floats: where you don't care about answers being exact, either (1) because calculation speed is more important than exactness, or (2) because your inputs or computations involve uncertainty anyway, so it doesn't matter. This is more likely to be the case in, say, physics than it is in finance, but it's not impossible in the latter. For example, if you are a hedge fund and some model computes "the true price of this financial instrument is 214.55", you certainly want to buy if it's being sold for 200, and certainly don't if it's being sold for 250, but if it's being sold for 214.54, the correct interpretation is that _you aren't sure_. When people say "you should never use floats for currency", their error is in thinking that the only applications for currency are in accounting, billing, and so on. In those applications, one should indeed use a decimal type, because we do care about the rounding behavior exactly matching human customs.
- lordgilman 5y agoInteger cents or an arbitrary precision decimal type.
- shagie 5y agoHaving worked on a POS system, the issue of using cents alone is if you've got something like "11% rebate" and you need to deal with fractional cents. The arbitrary precision decimal type should be the default answer for currency until it is shown that the requirements no and at no time in the future will ever require fractional units of the smallest denomination. As an aside, this may be constrained by the systems that the data is persisted into too... the Buffett Overflow is a real thing ( https://news.ycombinator.com/item?id=27044044 https://news.ycombinator.com/item?id=27044044 ).
- _ZeD_ 5y agopython has the `decimal` module in the stdlib
- tyingq 5y agoThere's no one answer, but decimal counts of the smallest unit that needs to be measured is common. Like pennies in the US, or maybe "number of 1/10 pennies" if there's things like gasoline tax.
- bencollier49 5y agoSay what you like about COBOL, but it got this stuff right.
- bpicolo 5y agoYou can use integers instead of decimal if you're using the smallest unit.
- SmooL 5y agoYeah, you probably want to use some sort of decimal package for a configurable amount of precision, and then use strings when serializing/storing the values
- pizza234 5y agoThis is a complex topic, mainly for two reasons: 1. it works on two layers (storage and code) 2. there is a context to take care of. [Modern] programming languages have decimal/rational data types, which (within limits) are exact. Where this is not possible, and/or it's undesirable for any reason, just use an int and scale it manually (e.g. 1.05 dollars = int 105). However, point 2 is very problematic and important to consider. How do account 3 items that cost 1/3$ each (e.g. if in a bundle)? What if they're sold separately? This really depends on the requirements. My 20 cents: if you start a project, start storing currency in an exact form. Once a project grows, correcting the FP error problem is a big PITA (assuming it's realistically possible).
- XorNot 5y agoThe problem is also stupid people and companies. My last job they wanted me to invoice them hours worked, which was some number like 7.6. This number plays badly when you run it through GST and other things - you get repeaters. So I looked up common practice here, even tried asking finance who just said "be exact", and eventually settled on that below 1 cent fractions I would round up to the nearest cent in my favour for each line item. First invoice I hand them, they manually tally up all the line items and hours, and complain it's over by 55 cents. So I change it to give rounded line items but straight multiplied to the total - and they complain it doesn't match. Finally I just print decimal exact numbers (which are occasionally huge) and they stop complaining - because excel is now happy the sums match when they keep second guessing my invoices. All of this of course was irrelevant - I still had to put hours into their payroll system as well (which they checked against) and my contract specifically stated what my day rate was to be in lieu of notice. So how should you do currency? Probably in whatever form that matches how finance are using excel, which does it wrong.
- hobs 5y agoI wish this was untrue, but I have spent years hearing the words "why dont my reports match?" - no amount of logic, diagrams, explaining, the next quarter or instance - "why dont my reports match?" BECAUSE EXCEL SUCKS MY DUDE.
- 5y ago
- bidirectional 5y agoEvery front office finance project I have ever worked on has used floating point, so take the dogma with a grain of salt. It depends entirely on the context.
- dirkt 5y agoAnd the all suffer from rounding error problems? I mean, fixed point and a specific type for currency (which also should include the denomination, while we are at it) are not rocket science. Spreadsheets get that right, at least.
- bidirectional 5y agoExcel uses IEEE-754 floating point, so I don't get what you mean with the spreadsheet comment. It has formatting around this which rounds and adds currency symbols, but it's floating point you're working with. Rounding error doesn't matter on these types of financial applications. It's the less glamorous accounting work that has to bother with that. They're not rocket science, but they're unnecessary, and would still be off anyway. Try and calculate compound interest with your fixed point numbers.
- jhugo 5y agoThey probably just accumulate the rounding errors into an account and write it off periodically without even realising why it happens.
- bidirectional 5y agoNo, it's just that we're in the realm of predictions and modelling, not accounting. If you're constructing a curve to forecast 50 years of interest rates from a limited set of instruments, you're already accepting a margin of error orders of magnitude greater than the inaccuracies introduced by floating point. The models also use transcendental functions which cannot be accurately calculated with fixed point, rationals, integers etc.
- 5y ago
- trevor-e 5y agoSomeone already mentioned there's a `decimal` package in Python that's better suited for currency. Back when I was a Java developer we used this: https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html https://docs.oracle.com/javase/7/docs/api/java/math/BigDecim...
- wodenokoto 5y agoA lot of good answers, but they mostly relate to accounting types of problems (which granted, is what you need to do with currency data 99% of the time) I’d just add that if you are building a price prediction model, floats are probably what you need.
- tyingq 5y agoThe example code is the start of an expense tracking tool...
- kkirsche 5y agoThe Decimal class is one way if you roll your own. py-moneyed seems to be a well maintained library though I haven’t used it. Disclaimer: I only work with currency in hobby projects.
- spamizbad 5y agoFor Python, I prefer decimal.Decimal[1]. When you serialize, you can either convert it to a string (and then have your deserializer know the field type and automatically encode it back into a decimal) OR just agree all numeric values can only be ints or decimals. You can pass parse_float=decimal.Decimal to json.loads[2] to make this easier. My most obnoxious and spicy programming take is that ints an decimals should be built-in and floats should require imports. I understand why though: Decimal encoding isn't anywhere near as standardized as other numeric types like integers or floating-point numbers. [1] https://docs.python.org/3/library/decimal.html https://docs.python.org/3/library/decimal.html [2] https://docs.python.org/3/library/json.html https://docs.python.org/3/library/json.html
- dragonwriter 5y ago> My most obnoxious and spicy programming take is that ints an decimals should be built-in and floats should require imports I don't care about making inexact numbers require imports, but the most natural literal formats should produce exact integers, decimals, and/or rationals.
- dangerbird2 5y agoEither a fixed-point decimal (i.e. an integer with the ones representing 1/100, 1/1000, etc. of a dollar, or a ratio type if you need arbitrary precision.
- Quekid5 5y ago> ratio type if you need arbitrary precision. This is the better default, so I'd ditch the qualifier, personally. At the very least when it comes to the persistent storage of monetary amounts. People often start out thinking that they won't need arbitrary precision until that one little requirement trickles into the backlog... Arbitrary precision rationals handles all the artithmetic you could reasonably want to do with monetary amounts and it lets you decide where to round at display time (or when generating a final invoice or whatever), so there's no information loss.
- thayne 5y agoAn integer of the smallest denomination. For example, cents for the American dollar. And you probably would want to wrap it in a custom type to simplify displaying it properly, and maybe handle different currencies. If you language has a fixed point type that might also be appropriate, but that's pretty rare, and wouldn't work for currencies that aren't decimal (like the old british pound system).
- biztos 5y agoDo they still use fractional cents (or whatever) in finance? https://money.howstuffworks.com/personal-finance/financial-planning/stock-market-use-fractions.htm https://money.howstuffworks.com/personal-finance/financial-p...
- TchoBeer 5y agoWhat if I'm calculating sales tax? Can't use an integer anymore.
- kyllo 5y agoYes, you can. There are algorithms for rounding up, rounding down, rounding to nearest, and banker's rounding, on the results of integer division. This is a solved problem.
- kyrra 5y agoTo pile on, here's a copy/paste from when this was asked a few days ago: Googler, opinions are my own. Over in payments, we use micros regularly, as documented here: https://developers.google.com/standard-payments/reference/glossary#micros https://developers.google.com/standard-payments/reference/gl... GCP on there other hand has standardized on unit + nano. They use this for money and time. So unit would 1 second or 1 dollar, then the nano field allows more precision. You can see an example here with the unitPrice field: https://cloud.google.com/billing/v1/how-tos/catalog-api#getting_the_list_of_skus_for_a_service https://cloud.google.com/billing/v1/how-tos/catalog-api#gett... Copy/paste the GCP doc portion that is relevant here: > [UNITS] is the whole units of the amount. For example if currencyCode is "USD", then 1 unit is one US dollar. > [NANOS] is the number of nano (10^-9) units of the amount. The value must be between -999,999,999 and +999,999,999 inclusive. If units is positive, nanos must be positive or zero. If units is zero, nanos can be positive, zero, or negative. If units is negative, nanos must be negative or zero. For example $-1.75 is represented as units=-1 and nanos=-750,000,000.
- marcosdumay 5y agoEach country has a law or something similar that states how people should calculate over prices. The usual is to use decimal numbers with fixed precision (the actual precision varies from one country to another), and I don't know of any modern exception. But as late as the 90's there were non-decimal monetary systems around the world, so if you are saving any historic data, you may need something more complex.
- dragonwriter 5y ago> Dumb question, but what is the proper way to handle currency? In python, for exact applications (not many kinds of modeling, where floats are probably right), decimal.Decimal is usually the right answer, but fractions.Fraction is sometimes more appropriate, and if you are using NumPy or tools dependent on it, using integers (representing decimals multiplied by the right power of 10 to get the minimum unit in the ones position) is probably better.